[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]
[libeufin] branch master updated: Taler integration API handlers.
From: |
gnunet |
Subject: |
[libeufin] branch master updated: Taler integration API handlers. |
Date: |
Wed, 20 Sep 2023 16:30:48 +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 ddef3b15 Taler integration API handlers.
ddef3b15 is described below
commit ddef3b151f6cf3a2b4884698c0bdde2b046b0314
Author: MS <ms@taler.net>
AuthorDate: Wed Sep 20 16:30:31 2023 +0200
Taler integration API handlers.
---
bank/src/main/kotlin/tech/libeufin/bank/Main.kt | 3 +-
bank/src/main/kotlin/tech/libeufin/bank/helpers.kt | 39 +++++++-
.../tech/libeufin/bank/talerIntegrationHandlers.kt | 106 +++++++++++++++++++++
.../kotlin/tech/libeufin/bank/talerWebHandlers.kt | 21 ----
bank/src/main/kotlin/tech/libeufin/bank/types.kt | 59 +++++++++++-
5 files changed, 204 insertions(+), 24 deletions(-)
diff --git a/bank/src/main/kotlin/tech/libeufin/bank/Main.kt
b/bank/src/main/kotlin/tech/libeufin/bank/Main.kt
index cf5b48a9..b0e9e46c 100644
--- a/bank/src/main/kotlin/tech/libeufin/bank/Main.kt
+++ b/bank/src/main/kotlin/tech/libeufin/bank/Main.kt
@@ -226,6 +226,7 @@ val webApp: Application.() -> Unit = {
this.tokenHandlers()
this.transactionsHandlers()
this.talerWebHandlers()
- // this.walletIntegrationHandlers()
+ this.talerIntegrationHandlers()
+ // this.talerWireGatewayHandlers()
}
}
\ No newline at end of file
diff --git a/bank/src/main/kotlin/tech/libeufin/bank/helpers.kt
b/bank/src/main/kotlin/tech/libeufin/bank/helpers.kt
index 59ddb318..9487679a 100644
--- a/bank/src/main/kotlin/tech/libeufin/bank/helpers.kt
+++ b/bank/src/main/kotlin/tech/libeufin/bank/helpers.kt
@@ -27,6 +27,7 @@ import net.taler.wallet.crypto.Base32Crockford
import tech.libeufin.util.*
import java.lang.NumberFormatException
import java.net.URL
+import java.util.*
fun ApplicationCall.expectUriComponent(componentName: String) =
this.maybeUriComponent(componentName) ?: throw badRequest(
@@ -369,4 +370,40 @@ fun getTalerWithdrawUri(baseUrl: String, woId: String) =
}
pathSegments.add("taler-integration/${woId}")
this.appendPathSegments(pathSegments)
- }
\ No newline at end of file
+ }
+
+fun getWithdrawalConfirmUrl(baseUrl: String, wopId: String) =
+ url {
+ val baseUrlObj = URL(baseUrl)
+ protocol = URLProtocol(name = baseUrlObj.protocol, defaultPort = -1)
+ host = baseUrlObj.host
+ // Removing potential double slashes:
+ baseUrlObj.path.split("/").forEach {
+ this.appendPathSegments(it)
+ }
+ // Completing the endpoint:
+ this.appendPathSegments("${wopId}/confirm")
+ }
+
+
+/**
+ * This handler factors out the checking of the query param
+ * and the retrieval of the related withdrawal database row.
+ * It throws 404 if the operation is not found, and throws 400
+ * if the query param doesn't parse into a UUID. Currently
+ * used by the Taler Web/SPA and Integration API handlers.
+ */
+fun getWithdrawal(opIdParam: String): TalerWithdrawalOperation {
+ val opId = try {
+ UUID.fromString(opIdParam)
+ } catch (e: Exception) {
+ logger.error(e.message)
+ throw badRequest("withdrawal_id query parameter was malformed")
+ }
+ val op = db.talerWithdrawalGet(opId)
+ ?: throw notFound(
+ hint = "Withdrawal operation ${opIdParam} not found",
+ talerEc = TalerErrorCode.TALER_EC_END
+ )
+ return op
+}
diff --git
a/bank/src/main/kotlin/tech/libeufin/bank/talerIntegrationHandlers.kt
b/bank/src/main/kotlin/tech/libeufin/bank/talerIntegrationHandlers.kt
new file mode 100644
index 00000000..ef66e7ef
--- /dev/null
+++ b/bank/src/main/kotlin/tech/libeufin/bank/talerIntegrationHandlers.kt
@@ -0,0 +1,106 @@
+/*
+ * This file is part of LibEuFin.
+ * Copyright (C) 2019 Stanisci and Dold.
+
+ * 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/>
+ */
+
+/* This file contains the Taler Integration API endpoints,
+* that are typically requested by wallets. */
+package tech.libeufin.bank
+
+import io.ktor.server.application.*
+import io.ktor.server.request.*
+import io.ktor.server.response.*
+import io.ktor.server.routing.*
+import net.taler.common.errorcodes.TalerErrorCode
+import tech.libeufin.util.getBaseUrl
+
+fun Routing.talerIntegrationHandlers() {
+ get("/taler-integration/config") {
+ val internalCurrency: String = db.configGet("internal_currency")
+ ?: throw internalServerError("Currency not found")
+ call.respond(TalerIntegrationConfigResponse(currency =
internalCurrency))
+ return@get
+ }
+ // Note: wopid acts as an authentication token.
+ get("/taler-integration/withdrawal-operation/{wopid}") {
+ val wopid = call.expectUriComponent("wopid")
+ val op = getWithdrawal(wopid) // throws 404 if not found.
+ val relatedBankAccount =
db.bankAccountGetFromOwnerId(op.walletBankAccount)
+ if (relatedBankAccount == null)
+ throw internalServerError("Bank has a withdrawal not related to
any bank account.")
+ val suggestedExchange = db.configGet("suggested_exchange")
+ ?: throw internalServerError("Bank does not have an exchange to
suggest.")
+ val confirmUrl = getWithdrawalConfirmUrl(
+ baseUrl = call.request.getBaseUrl() ?: throw
internalServerError("Could not get bank own base URL."),
+ wopId = wopid
+ )
+ call.respond(BankWithdrawalOperationStatus(
+ aborted = op.aborted,
+ selection_done = op.selectionDone,
+ transfer_done = op.confirmationDone,
+ amount = op.amount.toString(),
+ sender_wire = relatedBankAccount.internalPaytoUri,
+ suggested_exchange = suggestedExchange,
+ confirm_transfer_url = confirmUrl
+ ))
+ return@get
+ }
+ post("/taler-integration/withdrawal-operation/{wopid}") {
+ val wopid = call.expectUriComponent("wopid")
+ val req = call.receive<BankWithdrawalOperationPostRequest>()
+ val op = getWithdrawal(wopid) // throws 404 if not found.
+ if (op.selectionDone) {
+ // idempotency
+ if (op.selectedExchangePayto != req.selected_exchange &&
+ op.reservePub != req.reserve_pub)
+ throw conflict(
+ hint = "Cannot select different exchange and reserve pub.
under the same withdrawal operation",
+ talerEc =
TalerErrorCode.TALER_EC_BANK_WITHDRAWAL_OPERATION_RESERVE_SELECTION_CONFLICT
+ )
+ }
+ val dbSuccess: Boolean = if (!op.selectionDone) {
+ val exchangePayto = req.selected_exchange
+ ?: (db.configGet("suggested_exchange")
+ ?: throw internalServerError("Suggested exchange not
found")
+ )
+ db.talerWithdrawalSetDetails(
+ op.withdrawalUuid,
+ exchangePayto,
+ req.reserve_pub
+ )
+ }
+ else // DB succeeded in the past.
+ true
+ if (!dbSuccess)
+ // Whatever the problem, the bank missed it: respond 500.
+ throw internalServerError("Bank failed at selecting the
withdrawal.")
+ val resp = BankWithdrawalOperationPostResponse(
+ transfer_done = op.confirmationDone,
+ confirm_transfer_url = if (!op.confirmationDone)
+ getWithdrawalConfirmUrl(
+ baseUrl = call.request.getBaseUrl()
+ ?: throw internalServerError("Could not get bank own
base URL."),
+ wopId = wopid
+ )
+ else
+ null
+ )
+ call.respond(resp)
+ return@post
+ }
+}
+
diff --git a/bank/src/main/kotlin/tech/libeufin/bank/talerWebHandlers.kt
b/bank/src/main/kotlin/tech/libeufin/bank/talerWebHandlers.kt
index 33a334ed..f449cb54 100644
--- a/bank/src/main/kotlin/tech/libeufin/bank/talerWebHandlers.kt
+++ b/bank/src/main/kotlin/tech/libeufin/bank/talerWebHandlers.kt
@@ -36,27 +36,6 @@ import tech.libeufin.util.getBaseUrl
import tech.libeufin.util.getNowUs
import java.util.*
-/**
- * This handler factors out the checking of the query param
- * and the retrieval of the related withdrawal database row.
- * It throws 404 if the operation is not found, and throws 400
- * if the query param doesn't parse into an UUID.
- */
-private fun getWithdrawal(opIdParam: String): TalerWithdrawalOperation {
- val opId = try {
- UUID.fromString(opIdParam)
- } catch (e: Exception) {
- logger.error(e.message)
- throw badRequest("withdrawal_id query parameter was malformed")
- }
- val op = db.talerWithdrawalGet(opId)
- ?: throw notFound(
- hint = "Withdrawal operation ${opIdParam} not found",
- talerEc = TalerErrorCode.TALER_EC_END
- )
- return op
-}
-
fun Routing.talerWebHandlers() {
post("/accounts/{USERNAME}/withdrawals") {
val c = call.myAuth(TokenScope.readwrite) ?: throw unauthorized()
diff --git a/bank/src/main/kotlin/tech/libeufin/bank/types.kt
b/bank/src/main/kotlin/tech/libeufin/bank/types.kt
index fe6d2488..8daaf8ce 100644
--- a/bank/src/main/kotlin/tech/libeufin/bank/types.kt
+++ b/bank/src/main/kotlin/tech/libeufin/bank/types.kt
@@ -439,4 +439,61 @@ enum class WithdrawalConfirmationResult {
OP_NOT_FOUND,
EXCHANGE_NOT_FOUND,
BALANCE_INSUFFICIENT
-}
\ No newline at end of file
+}
+
+// GET /config response from the Taler Integration API.
+@Serializable
+data class TalerIntegrationConfigResponse(
+ val name: String = "taler-bank-integration",
+ val version: String = "0:0:0:",
+ val currency: String
+)
+
+// Withdrawal status as spec'd in the Taler Integration API.
+@Serializable
+data class BankWithdrawalOperationStatus(
+ // Indicates whether the withdrawal was aborted.
+ val aborted: Boolean,
+
+ /* Has the wallet selected parameters for the withdrawal operation
+ (exchange and reserve public key) and successfully sent it
+ to the bank? */
+ val selection_done: Boolean,
+
+ /* The transfer has been confirmed and registered by the bank.
+ Does not guarantee that the funds have arrived at the exchange
+ already. */
+ val transfer_done: Boolean,
+
+ /* Amount that will be withdrawn with this operation
+ (raw amount without fee considerations). */
+ val amount: String,
+
+ /* Bank account of the customer that is withdrawing, as a
+ ``payto`` URI. */
+ val sender_wire: String? = null,
+
+ // Suggestion for an exchange given by the bank.
+ val suggested_exchange: String? = null,
+
+ /* URL that the user needs to navigate to in order to
+ complete some final confirmation (e.g. 2FA).
+ It may contain withdrawal operation id */
+ val confirm_transfer_url: String? = null,
+
+ // Wire transfer types supported by the bank.
+ val wire_types: MutableList<String> = mutableListOf("iban")
+)
+
+// Selection request on a Taler withdrawal.
+@Serializable
+data class BankWithdrawalOperationPostRequest(
+ val reserve_pub: String,
+ val selected_exchange: String? = null // Use suggested exchange if that's
missing.
+)
+
+@Serializable
+data class BankWithdrawalOperationPostResponse(
+ val transfer_done: Boolean,
+ val confirm_transfer_url: String? = null
+)
\ No newline at end of file
--
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: Taler integration API handlers.,
gnunet <=