gnunet-svn
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

[libeufin] 02/02: refactoring, adapt to core bank API withdrawal change


From: gnunet
Subject: [libeufin] 02/02: refactoring, adapt to core bank API withdrawal change
Date: Sun, 24 Sep 2023 14:18:56 +0200

This is an automated email from the git hooks/post-receive script.

dold pushed a commit to branch master
in repository libeufin.

commit fb40741be92b179dba8fc416f993c59f1a6850aa
Author: Florian Dold <florian@dold.me>
AuthorDate: Sun Sep 24 14:18:56 2023 +0200

    refactoring, adapt to core bank API withdrawal change
---
 .../kotlin/tech/libeufin/bank/Authentication.kt    |  39 ++
 .../libeufin/bank/{types.kt => BankMessages.kt}    |  63 +++-
 .../tech/libeufin/bank/CorebankApiHandlers.kt      | 404 ++++++++++-----------
 bank/src/main/kotlin/tech/libeufin/bank/Main.kt    |  34 +-
 .../tech/libeufin/bank/WireGatewayApiHandlers.kt   |   9 +-
 bank/src/main/kotlin/tech/libeufin/bank/helpers.kt | 290 ++++++---------
 contrib/libeufin-bank.sample.conf                  |   2 +-
 util/src/main/kotlin/HTTP.kt                       |  11 +-
 8 files changed, 395 insertions(+), 457 deletions(-)

diff --git a/bank/src/main/kotlin/tech/libeufin/bank/Authentication.kt 
b/bank/src/main/kotlin/tech/libeufin/bank/Authentication.kt
new file mode 100644
index 00000000..6054877e
--- /dev/null
+++ b/bank/src/main/kotlin/tech/libeufin/bank/Authentication.kt
@@ -0,0 +1,39 @@
+package tech.libeufin.bank
+
+import io.ktor.http.*
+import io.ktor.server.application.*
+import net.taler.common.errorcodes.TalerErrorCode
+import tech.libeufin.util.getAuthorizationDetails
+import tech.libeufin.util.getAuthorizationRawHeader
+
+/**
+ * This function tries to authenticate the call according
+ * to the scheme that is mentioned in the Authorization header.
+ * The allowed schemes are either 'HTTP basic auth' or 'bearer token'.
+ *
+ * requiredScope can be either "readonly" or "readwrite".
+ *
+ * Returns the authenticated customer, or null if they failed.
+ */
+fun ApplicationCall.authenticateBankRequest(db: Database, requiredScope: 
TokenScope): Customer? {
+    // Extracting the Authorization header.
+    val header = getAuthorizationRawHeader(this.request) ?: throw badRequest(
+        "Authorization header not found.",
+        TalerErrorCode.TALER_EC_GENERIC_HTTP_HEADERS_MALFORMED
+    )
+    val authDetails = getAuthorizationDetails(header) ?: throw badRequest(
+        "Authorization is invalid.",
+        TalerErrorCode.TALER_EC_GENERIC_HTTP_HEADERS_MALFORMED
+    )
+    return when (authDetails.scheme) {
+        "Basic" -> doBasicAuth(db, authDetails.content)
+        "Bearer" -> doTokenAuth(db, authDetails.content, requiredScope)
+        else -> throw LibeufinBankException(
+            httpStatus = HttpStatusCode.Unauthorized,
+            talerError = TalerError(
+                code = TalerErrorCode.TALER_EC_GENERIC_UNAUTHORIZED.code,
+                hint = "Authorization method wrong or not supported."
+            )
+        )
+    }
+}
\ No newline at end of file
diff --git a/bank/src/main/kotlin/tech/libeufin/bank/types.kt 
b/bank/src/main/kotlin/tech/libeufin/bank/BankMessages.kt
similarity index 94%
rename from bank/src/main/kotlin/tech/libeufin/bank/types.kt
rename to bank/src/main/kotlin/tech/libeufin/bank/BankMessages.kt
index 86c5dbf7..b12292e3 100644
--- a/bank/src/main/kotlin/tech/libeufin/bank/types.kt
+++ b/bank/src/main/kotlin/tech/libeufin/bank/BankMessages.kt
@@ -23,17 +23,20 @@ import io.ktor.http.*
 import io.ktor.server.application.*
 import kotlinx.serialization.Contextual
 import kotlinx.serialization.Serializable
-import java.io.Serial
 import java.util.*
 
-// Allowed lengths for fractional digits in amounts.
+/**
+ * Allowed lengths for fractional digits in amounts.
+ */
 enum class FracDigits(howMany: Int) {
     TWO(2),
     EIGHT(8)
 }
 
 
-// It contains the number of microseconds since the Epoch.
+/**
+ * Timestamp containing the number of seconds since epoch.
+ */
 @Serializable
 data class Timestamp(
     val t_s: Long // FIXME (?): not supporting "never" at the moment.
@@ -86,9 +89,10 @@ data class RegisterAccountRequest(
     val internal_payto_uri: String? = null
 )
 
-/* Internal representation of relative times.  The
-* "forever" case is represented with Long.MAX_VALUE.
-*/
+/**
+ * Internal representation of relative times.  The
+ * "forever" case is represented with Long.MAX_VALUE.
+ */
 data class RelativeTime(
     val d_us: Long
 )
@@ -341,19 +345,30 @@ data class Config(
     val fiat_currency: String? = null
 )
 
-// GET /accounts/$USERNAME response.
+@Serializable
+data class Balance(
+    // FIXME: Should not be a string
+    val amount: String,
+    // FIXME: Should not be a string
+    val credit_debit_indicator: String,
+)
+
+/**
+ * GET /accounts/$USERNAME response.
+ */
 @Serializable
 data class AccountData(
     val name: String,
-    val balance: String,
+    val balance: Balance,
     val payto_uri: String,
     val debit_threshold: String,
     val contact_data: ChallengeContactData? = null,
     val cashout_payto_uri: String? = null,
-    val has_debit: Boolean
 )
 
-// Type of POST /transactions
+/**
+ * Response type of corebank API transaction initiation.
+ */
 @Serializable
 data class BankAccountTransactionCreate(
     val payto_uri: String,
@@ -457,7 +472,9 @@ data class TalerIntegrationConfigResponse(
     val currency: String
 )
 
-// Withdrawal status as spec'd in the Taler Integration API.
+/**
+ * Withdrawal status as specified in the Taler Integration API.
+ */
 @Serializable
 data class BankWithdrawalOperationStatus(
     // Indicates whether the withdrawal was aborted.
@@ -493,7 +510,9 @@ data class BankWithdrawalOperationStatus(
     val wire_types: MutableList<String> = mutableListOf("iban")
 )
 
-// Selection request on a Taler withdrawal.
+/**
+ * Selection request on a Taler withdrawal.
+ */
 @Serializable
 data class BankWithdrawalOperationPostRequest(
     val reserve_pub: String,
@@ -521,7 +540,9 @@ data class AddIncomingRequest(
     val debit_account: String
 )
 
-// Response to /admin/add-incoming
+/**
+ * Response to /admin/add-incoming
+ */
 @Serializable
 data class AddIncomingResponse(
     val timestamp: Long,
@@ -535,14 +556,18 @@ data class TWGConfigResponse(
     val currency: String
 )
 
-// Response of a TWG /history/incoming call.
+/**
+ * Response of a TWG /history/incoming call.
+ */
 @Serializable
 data class IncomingHistory(
     val incoming_transactions: MutableList<IncomingReserveTransaction> = 
mutableListOf(),
     val credit_account: String // Receiver's Payto URI.
 )
 
-// TWG's incoming payment record.
+/**
+ * TWG's incoming payment record.
+ */
 @Serializable
 data class IncomingReserveTransaction(
     val type: String = "RESERVE",
@@ -553,7 +578,9 @@ data class IncomingReserveTransaction(
     val reserve_pub: String
 )
 
-// TWG's request to pay a merchant.
+/**
+ * TWG's request to pay a merchant.
+ */
 @Serializable
 data class TransferRequest(
     val request_uid: String,
@@ -564,7 +591,9 @@ data class TransferRequest(
     val credit_account: String
 )
 
-// TWG's response to merchant payouts
+/**
+ * TWG's response to merchant payouts
+ */
 @Serializable
 data class TransferResponse(
     val timestamp: Long,
diff --git a/bank/src/main/kotlin/tech/libeufin/bank/CorebankApiHandlers.kt 
b/bank/src/main/kotlin/tech/libeufin/bank/CorebankApiHandlers.kt
index 49421402..bfae12c4 100644
--- a/bank/src/main/kotlin/tech/libeufin/bank/CorebankApiHandlers.kt
+++ b/bank/src/main/kotlin/tech/libeufin/bank/CorebankApiHandlers.kt
@@ -24,15 +24,13 @@ fun Routing.accountsMgmtHandlers(db: Database, ctx: 
BankApplicationContext) {
     delete("/accounts/{USERNAME}/token") {
         throw internalServerError("Token deletion not implemented.")
     }
-    
+
     post("/accounts/{USERNAME}/token") {
-        val customer = call.myAuth(db, TokenScope.refreshable) ?: throw 
unauthorized("Authentication failed")
+        val customer = call.authenticateBankRequest(db, 
TokenScope.refreshable) ?: throw unauthorized("Authentication failed")
         val endpointOwner = call.maybeUriComponent("USERNAME")
-        if (customer.login != endpointOwner)
-            throw forbidden(
-                "User has no rights on this enpoint",
-                TalerErrorCode.TALER_EC_END // FIXME: need generic forbidden
-            )
+        if (customer.login != endpointOwner) throw forbidden(
+            "User has no rights on this enpoint", TalerErrorCode.TALER_EC_END 
// FIXME: need generic forbidden
+        )
         val maybeAuthToken = call.getAuthToken()
         val req = call.receive<TokenRequest>()
         /**
@@ -44,33 +42,29 @@ fun Routing.accountsMgmtHandlers(db: Database, ctx: 
BankApplicationContext) {
             val refreshingToken = db.bearerTokenGet(tokenBytes) ?: throw 
internalServerError(
                 "Token used to auth not found in the database!"
             )
-            if (refreshingToken.scope == TokenScope.readonly && req.scope == 
TokenScope.readwrite)
-                throw forbidden(
-                    "Cannot generate RW token from RO",
-                    
TalerErrorCode.TALER_EC_GENERIC_TOKEN_PERMISSION_INSUFFICIENT
-                )
+            if (refreshingToken.scope == TokenScope.readonly && req.scope == 
TokenScope.readwrite) throw forbidden(
+                "Cannot generate RW token from RO", 
TalerErrorCode.TALER_EC_GENERIC_TOKEN_PERMISSION_INSUFFICIENT
+            )
         }
         val tokenBytes = ByteArray(32).apply {
-            java.util.Random().nextBytes(this)
+            Random().nextBytes(this)
         }
         val maxDurationTime: Long = ctx.maxAuthTokenDurationUs
-        if (req.duration != null && req.duration.d_us > maxDurationTime)
-            throw forbidden(
-                "Token duration bigger than bank's limit",
-                // FIXME: define new EC for this case.
-                TalerErrorCode.TALER_EC_END
-            )
-        val tokenDurationUs  = req.duration?.d_us ?: TOKEN_DEFAULT_DURATION_US
+        if (req.duration != null && req.duration.d_us > maxDurationTime) throw 
forbidden(
+            "Token duration bigger than bank's limit",
+            // FIXME: define new EC for this case.
+            TalerErrorCode.TALER_EC_END
+        )
+        val tokenDurationUs = req.duration?.d_us ?: TOKEN_DEFAULT_DURATION_US
         val customerDbRow = customer.dbRowId ?: throw internalServerError(
             "Could not get customer '${customer.login}' database row ID"
         )
         val expirationTimestampUs: Long = getNowUs() + tokenDurationUs
-        if (expirationTimestampUs < tokenDurationUs)
-            throw badRequest(
-                "Token duration caused arithmetic overflow",
-                // FIXME: need dedicate EC (?)
-                talerErrorCode = TalerErrorCode.TALER_EC_END
-            )
+        if (expirationTimestampUs < tokenDurationUs) throw badRequest(
+            "Token duration caused arithmetic overflow",
+            // FIXME: need dedicate EC (?)
+            talerErrorCode = TalerErrorCode.TALER_EC_END
+        )
         val token = BearerToken(
             bankCustomer = customerDbRow,
             content = tokenBytes,
@@ -79,12 +73,10 @@ fun Routing.accountsMgmtHandlers(db: Database, ctx: 
BankApplicationContext) {
             scope = req.scope,
             isRefreshable = req.refreshable
         )
-        if (!db.bearerTokenCreate(token))
-            throw internalServerError("Failed at inserting new token in the 
database")
+        if (!db.bearerTokenCreate(token)) throw internalServerError("Failed at 
inserting new token in the database")
         call.respond(
             TokenSuccessResponse(
-                access_token = Base32Crockford.encode(tokenBytes),
-                expiration = Timestamp(
+                access_token = Base32Crockford.encode(tokenBytes), expiration 
= Timestamp(
                     t_s = expirationTimestampUs / 1000000L
                 )
             )
@@ -95,27 +87,23 @@ fun Routing.accountsMgmtHandlers(db: Database, ctx: 
BankApplicationContext) {
     post("/accounts") {
         // check if only admin is allowed to create new accounts
         if (ctx.restrictRegistration) {
-            val customer: Customer? = call.myAuth(db, TokenScope.readwrite)
-            if (customer == null || customer.login != "admin")
-                throw LibeufinBankException(
-                    httpStatus = HttpStatusCode.Unauthorized,
-                    talerError = TalerError(
-                        code = TalerErrorCode.TALER_EC_BANK_LOGIN_FAILED.code,
-                        hint = "Either 'admin' not authenticated or an 
ordinary user tried this operation."
-                    )
+            val customer: Customer? = call.authenticateBankRequest(db, 
TokenScope.readwrite)
+            if (customer == null || customer.login != "admin") throw 
LibeufinBankException(
+                httpStatus = HttpStatusCode.Unauthorized, talerError = 
TalerError(
+                    code = TalerErrorCode.TALER_EC_BANK_LOGIN_FAILED.code,
+                    hint = "Either 'admin' not authenticated or an ordinary 
user tried this operation."
                 )
+            )
         }
         // auth passed, proceed with activity.
         val req = call.receive<RegisterAccountRequest>()
         // Prohibit reserved usernames:
-        if (req.username == "admin" || req.username == "bank")
-            throw LibeufinBankException(
-                httpStatus = HttpStatusCode.Conflict,
-                talerError = TalerError(
-                    code = GENERIC_UNDEFINED, // FIXME: this waits GANA.
-                    hint = "Username '${req.username}' is reserved."
-                )
+        if (req.username == "admin" || req.username == "bank") throw 
LibeufinBankException(
+            httpStatus = HttpStatusCode.Conflict, talerError = TalerError(
+                code = GENERIC_UNDEFINED, // FIXME: this waits GANA.
+                hint = "Username '${req.username}' is reserved."
             )
+        )
         // Checking idempotency.
         val maybeCustomerExists = db.customerGetFromLogin(req.username)
         // Can be null if previous call crashed before completion.
@@ -124,24 +112,19 @@ fun Routing.accountsMgmtHandlers(db: Database, ctx: 
BankApplicationContext) {
             db.bankAccountGetFromOwnerId(this.expectRowId())
         }
         if (maybeCustomerExists != null && maybeHasBankAccount != null) {
-            tech.libeufin.bank.logger.debug("Registering username was found: 
${maybeCustomerExists.login}")
+            logger.debug("Registering username was found: 
${maybeCustomerExists.login}")
             // Checking _all_ the details are the same.
             val isIdentic =
-                maybeCustomerExists.name == req.name &&
-                        maybeCustomerExists.email == 
req.challenge_contact_data?.email &&
-                        maybeCustomerExists.phone == 
req.challenge_contact_data?.phone &&
-                        maybeCustomerExists.cashoutPayto == 
req.cashout_payto_uri &&
-                        CryptoUtil.checkpw(req.password, 
maybeCustomerExists.passwordHash) &&
-                        maybeHasBankAccount.isPublic == req.is_public &&
-                        maybeHasBankAccount.isTalerExchange == 
req.is_taler_exchange &&
-                        maybeHasBankAccount.internalPaytoUri == 
req.internal_payto_uri
+                maybeCustomerExists.name == req.name && 
maybeCustomerExists.email == req.challenge_contact_data?.email && 
maybeCustomerExists.phone == req.challenge_contact_data?.phone && 
maybeCustomerExists.cashoutPayto == req.cashout_payto_uri && CryptoUtil.checkpw(
+                    req.password,
+                    maybeCustomerExists.passwordHash
+                ) && maybeHasBankAccount.isPublic == req.is_public && 
maybeHasBankAccount.isTalerExchange == req.is_taler_exchange && 
maybeHasBankAccount.internalPaytoUri == req.internal_payto_uri
             if (isIdentic) {
                 call.respond(HttpStatusCode.Created)
                 return@post
             }
             throw LibeufinBankException(
-                httpStatus = HttpStatusCode.Conflict,
-                talerError = TalerError(
+                httpStatus = HttpStatusCode.Conflict, talerError = TalerError(
                     code = GENERIC_UNDEFINED, // GANA needs this.
                     hint = "Idempotency check failed."
                 )
@@ -159,8 +142,7 @@ fun Routing.accountsMgmtHandlers(db: Database, ctx: 
BankApplicationContext) {
             passwordHash = CryptoUtil.hashpw(req.password),
         )
         val newCustomerRowId = db.customerCreate(newCustomer)
-            ?: throw internalServerError("New customer INSERT failed despite 
the previous checks")
-        /* Crashing here won't break data consistency between customers
+            ?: throw internalServerError("New customer INSERT failed despite 
the previous checks")/* Crashing here won't break data consistency between 
customers
          * and bank accounts, because of the idempotency.  Client will
          * just have to retry.  */
         val maxDebt = ctx.defaultCustomerDebtLimit
@@ -182,8 +164,8 @@ fun Routing.accountsMgmtHandlers(db: Database, ctx: 
BankApplicationContext) {
          */
         val bonusAmount = if (ctx.registrationBonusEnabled) 
ctx.registrationBonus else null
         if (bonusAmount != null) {
-            val adminCustomer = db.customerGetFromLogin("admin")
-                ?: throw internalServerError("Admin customer not found")
+            val adminCustomer =
+                db.customerGetFromLogin("admin") ?: throw 
internalServerError("Admin customer not found")
             val adminBankAccount = 
db.bankAccountGetFromOwnerId(adminCustomer.expectRowId())
                 ?: throw internalServerError("Admin bank account not found")
             val adminPaysBonus = BankInternalTransaction(
@@ -193,111 +175,104 @@ fun Routing.accountsMgmtHandlers(db: Database, ctx: 
BankApplicationContext) {
                 subject = "Registration bonus.",
                 transactionDate = getNowUs()
             )
-            when(db.bankTransactionCreate(adminPaysBonus)) {
-                Database.BankTransactionResult.NO_CREDITOR ->
-                    throw internalServerError("Bonus impossible: creditor not 
found, despite its recent creation.")
-                Database.BankTransactionResult.NO_DEBTOR ->
-                    throw internalServerError("Bonus impossible: admin not 
found.")
-                Database.BankTransactionResult.CONFLICT ->
-                    throw internalServerError("Bonus impossible: admin has 
insufficient balance.")
-                Database.BankTransactionResult.SUCCESS -> {/* continue the 
execution */}
+            when (db.bankTransactionCreate(adminPaysBonus)) {
+                Database.BankTransactionResult.NO_CREDITOR -> throw 
internalServerError("Bonus impossible: creditor not found, despite its recent 
creation.")
+
+                Database.BankTransactionResult.NO_DEBTOR -> throw 
internalServerError("Bonus impossible: admin not found.")
+
+                Database.BankTransactionResult.CONFLICT -> throw 
internalServerError("Bonus impossible: admin has insufficient balance.")
+
+                Database.BankTransactionResult.SUCCESS -> {/* continue the 
execution */
+                }
             }
         }
         call.respond(HttpStatusCode.Created)
         return@post
     }
+
     get("/accounts/{USERNAME}") {
-        val c = call.myAuth(db, TokenScope.readonly) ?: throw 
unauthorized("Login failed")
+        val c = call.authenticateBankRequest(db, TokenScope.readonly) ?: throw 
unauthorized("Login failed")
         val resourceName = call.maybeUriComponent("USERNAME") ?: throw 
badRequest(
-            hint = "No username found in the URI",
-            talerErrorCode = TalerErrorCode.TALER_EC_GENERIC_PARAMETER_MISSING
+            hint = "No username found in the URI", talerErrorCode = 
TalerErrorCode.TALER_EC_GENERIC_PARAMETER_MISSING
         )
         // Checking resource name only if Basic auth was used.
         // Successful tokens do not need this check, they just pass.
-        if (
-            ((c.login != resourceName)
-            && (c.login != "admin"))
-            && (call.getAuthToken() == null)
+        if (((c.login != resourceName) && (c.login != "admin")) && 
(call.getAuthToken() == null)) throw forbidden("No rights on the resource.")
+        val customerData = db.customerGetFromLogin(c.login)
+            ?: throw internalServerError("Customer '${c.login} despite being 
authenticated.'")
+        val customerInternalId = customerData.dbRowId
+            ?: throw internalServerError("Customer '${c.login} had no row ID 
despite it was found in the database.'")
+        val bankAccountData = db.bankAccountGetFromOwnerId(customerInternalId)
+            ?: throw internalServerError("Customer '${c.login} had no bank 
account despite they are customer.'")
+        val balance = Balance(
+            amount = bankAccountData.balance.toString(),
+            credit_debit_indicator = if (bankAccountData.hasDebt) { "debit" } 
else { "credit" }
+        )
+        call.respond(
+            AccountData(
+                name = customerData.name,
+                balance = balance,
+                debit_threshold = bankAccountData.maxDebt.toString(),
+                payto_uri = bankAccountData.internalPaytoUri,
+                contact_data = ChallengeContactData(
+                    email = customerData.email, phone = customerData.phone
+                ),
+                cashout_payto_uri = customerData.cashoutPayto,
             )
-            throw forbidden("No rights on the resource.")
-        val customerData = db.customerGetFromLogin(c.login) ?: throw 
internalServerError("Customer '${c.login} despite being authenticated.'")
-        val customerInternalId = customerData.dbRowId ?: throw 
internalServerError("Customer '${c.login} had no row ID despite it was found in 
the database.'")
-        val bankAccountData = db.bankAccountGetFromOwnerId(customerInternalId) 
?: throw internalServerError("Customer '${c.login} had no bank account despite 
they are customer.'")
-        call.respond(AccountData(
-            name = customerData.name,
-            balance = bankAccountData.balance.toString(),
-            debit_threshold = bankAccountData.maxDebt.toString(),
-            payto_uri = bankAccountData.internalPaytoUri,
-            contact_data = ChallengeContactData(
-                email = customerData.email,
-                phone = customerData.phone
-            ),
-            cashout_payto_uri = customerData.cashoutPayto,
-            has_debit = bankAccountData.hasDebt
-        ))
+        )
         return@get
     }
 
     post("/accounts/{USERNAME}/withdrawals") {
-        val c = call.myAuth(db, TokenScope.readwrite) ?: throw unauthorized()
+        val c = call.authenticateBankRequest(db, TokenScope.readwrite) ?: 
throw unauthorized()
         // Admin not allowed to withdraw in the name of customers:
         val accountName = call.expectUriComponent("USERNAME")
-        if (c.login != accountName)
-            throw unauthorized("User ${c.login} not allowed to withdraw for 
account '${accountName}'")
+        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.
         val b = db.bankAccountGetFromOwnerId(c.expectRowId())
             ?: throw internalServerError("Customer '${c.login}' lacks bank 
account.")
         val withdrawalAmount = parseTalerAmount(req.amount)
-        if (
-            !isBalanceEnough(
-                balance = b.expectBalance(),
-                due = withdrawalAmount,
-                maxDebt = b.maxDebt,
-                hasBalanceDebt = b.hasDebt
-            ))
-            throw forbidden(
-                hint = "Insufficient funds to withdraw with Taler",
-                talerErrorCode = TalerErrorCode.TALER_EC_NONE // FIXME: need 
EC.
+        if (!isBalanceEnough(
+                balance = b.expectBalance(), due = withdrawalAmount, maxDebt = 
b.maxDebt, hasBalanceDebt = b.hasDebt
             )
+        ) throw forbidden(
+            hint = "Insufficient funds to withdraw with Taler",
+            talerErrorCode = TalerErrorCode.TALER_EC_NONE // FIXME: need EC.
+        )
         // Auth and funds passed, create the operation now!
         val opId = UUID.randomUUID()
-        if(
-            !db.talerWithdrawalCreate(
-                opId,
-                b.expectRowId(),
-                withdrawalAmount
+        if (!db.talerWithdrawalCreate(
+                opId, b.expectRowId(), withdrawalAmount
             )
-        )
-            throw internalServerError("Bank failed at creating the withdraw 
operation.")
+        ) throw internalServerError("Bank failed at creating the withdraw 
operation.")
 
-        val bankBaseUrl = call.request.getBaseUrl()
-            ?: throw internalServerError("Bank could not find its own base 
URL")
-        call.respond(BankAccountCreateWithdrawalResponse(
-            withdrawal_id = opId.toString(),
-            taler_withdraw_uri = getTalerWithdrawUri(bankBaseUrl, 
opId.toString())
-        ))
+        val bankBaseUrl = call.request.getBaseUrl() ?: throw 
internalServerError("Bank could not find its own base URL")
+        call.respond(
+            BankAccountCreateWithdrawalResponse(
+                withdrawal_id = opId.toString(), taler_withdraw_uri = 
getTalerWithdrawUri(bankBaseUrl, opId.toString())
+            )
+        )
         return@post
     }
-    get("/accounts/{USERNAME}/withdrawals/{withdrawal_id}") {
-        val c = call.myAuth(db, TokenScope.readonly) ?: throw unauthorized()
-        val accountName = call.expectUriComponent("USERNAME")
-        // Admin allowed to see the details
-        if (c.login != accountName && c.login != "admin") throw forbidden()
-        // Permissions passed, get the information.
+
+    get("/withdrawals/{withdrawal_id}") {
         val op = getWithdrawal(db, call.expectUriComponent("withdrawal_id"))
-        call.respond(BankAccountGetWithdrawalResponse(
-            amount = op.amount.toString(),
-            aborted = op.aborted,
-            confirmation_done = op.confirmationDone,
-            selection_done = op.selectionDone,
-            selected_exchange_account = op.selectedExchangePayto,
-            selected_reserve_pub = op.reservePub
-        ))
+        call.respond(
+            BankAccountGetWithdrawalResponse(
+                amount = op.amount.toString(),
+                aborted = op.aborted,
+                confirmation_done = op.confirmationDone,
+                selection_done = op.selectionDone,
+                selected_exchange_account = op.selectedExchangePayto,
+                selected_reserve_pub = op.reservePub
+            )
+        )
         return@get
     }
-    post("/accounts/{USERNAME}/withdrawals/{withdrawal_id}/abort") {
-        val c = call.myAuth(db, TokenScope.readonly) ?: throw unauthorized()
+
+    post("/withdrawals/{withdrawal_id}/abort") {
+        val c = call.authenticateBankRequest(db, TokenScope.readonly) ?: throw 
unauthorized()
         // Admin allowed to abort.
         if (!call.getResourceName("USERNAME").canI(c)) throw forbidden()
         val op = getWithdrawal(db, call.expectUriComponent("withdrawal_id"))
@@ -308,52 +283,47 @@ fun Routing.accountsMgmtHandlers(db: Database, ctx: 
BankApplicationContext) {
         }
         // Op is found, it'll now fail only if previously confirmed (DB 
checks).
         if (!db.talerWithdrawalAbort(op.withdrawalUuid)) throw conflict(
-            hint = "Cannot abort confirmed withdrawal",
-            talerEc = TalerErrorCode.TALER_EC_END
+            hint = "Cannot abort confirmed withdrawal", talerEc = 
TalerErrorCode.TALER_EC_END
         )
         call.respondText("{}", ContentType.Application.Json)
         return@post
     }
-    post("/accounts/{USERNAME}/withdrawals/{withdrawal_id}/confirm") {
-        val c = call.myAuth(db, TokenScope.readwrite) ?: throw unauthorized()
+
+    post("/withdrawals/{withdrawal_id}/confirm") {
+        val c = call.authenticateBankRequest(db, TokenScope.readwrite) ?: 
throw unauthorized()
         // No admin allowed.
-        if(!call.getResourceName("USERNAME").canI(c, withAdmin = false)) throw 
forbidden()
+        if (!call.getResourceName("USERNAME").canI(c, withAdmin = false)) 
throw forbidden()
         val op = getWithdrawal(db, call.expectUriComponent("withdrawal_id"))
         // Checking idempotency:
         if (op.confirmationDone) {
             call.respondText("{}", ContentType.Application.Json)
             return@post
         }
-        if (op.aborted)
-            throw conflict(
-                hint = "Cannot confirm an aborted withdrawal",
-                talerEc = TalerErrorCode.TALER_EC_BANK_CONFIRM_ABORT_CONFLICT
-            )
+        if (op.aborted) throw conflict(
+            hint = "Cannot confirm an aborted withdrawal", talerEc = 
TalerErrorCode.TALER_EC_BANK_CONFIRM_ABORT_CONFLICT
+        )
         // Checking that reserve GOT indeed selected.
-        if (!op.selectionDone)
-            throw LibeufinBankException(
-                httpStatus = HttpStatusCode.UnprocessableEntity,
-                talerError = TalerError(
-                    hint = "Cannot confirm an unselected withdrawal",
-                    code = TalerErrorCode.TALER_EC_END.code
-                ))
-        /* Confirmation conditions are all met, now put the operation
+        if (!op.selectionDone) throw LibeufinBankException(
+            httpStatus = HttpStatusCode.UnprocessableEntity, talerError = 
TalerError(
+                hint = "Cannot confirm an unselected withdrawal", code = 
TalerErrorCode.TALER_EC_END.code
+            )
+        )/* Confirmation conditions are all met, now put the operation
          * to the selected state _and_ wire the funds to the exchange.
          * Note: 'when' helps not to omit more result codes, should more
          * be added.
          */
         when (db.talerWithdrawalConfirm(op.withdrawalUuid, getNowUs())) {
-            WithdrawalConfirmationResult.BALANCE_INSUFFICIENT ->
-                throw conflict(
-                    "Insufficient funds",
-                    TalerErrorCode.TALER_EC_END // FIXME: define EC for this.
-                )
+            WithdrawalConfirmationResult.BALANCE_INSUFFICIENT -> throw 
conflict(
+                "Insufficient funds", TalerErrorCode.TALER_EC_END // FIXME: 
define EC for this.
+            )
+
             WithdrawalConfirmationResult.OP_NOT_FOUND ->
                 /**
                  * Despite previous checks, the database _still_ did not
                  * find the withdrawal operation, that's on the bank.
                  */
                 throw internalServerError("Withdrawal operation 
(${op.withdrawalUuid}) not found")
+
             WithdrawalConfirmationResult.EXCHANGE_NOT_FOUND ->
                 /**
                  * That can happen because the bank did not check the exchange
@@ -361,22 +331,20 @@ fun Routing.accountsMgmtHandlers(db: Database, ctx: 
BankApplicationContext) {
                  * bank account got removed before this confirmation.
                  */
                 throw conflict(
-                    hint = "Exchange to withdraw from not found",
-                    talerEc = TalerErrorCode.TALER_EC_END // FIXME
-                )
-            WithdrawalConfirmationResult.CONFLICT ->
-                throw internalServerError("Bank didn't check for idempotency")
-            WithdrawalConfirmationResult.SUCCESS ->
-                call.respondText(
-                    "{}",
-                    ContentType.Application.Json
+                    hint = "Exchange to withdraw from not found", talerEc = 
TalerErrorCode.TALER_EC_END // FIXME
                 )
+
+            WithdrawalConfirmationResult.CONFLICT -> throw 
internalServerError("Bank didn't check for idempotency")
+
+            WithdrawalConfirmationResult.SUCCESS -> call.respondText(
+                "{}", ContentType.Application.Json
+            )
         }
         return@post
     }
 
     get("/accounts/{USERNAME}/transactions") {
-        val c = call.myAuth(db, TokenScope.readonly) ?: throw unauthorized()
+        val c = call.authenticateBankRequest(db, TokenScope.readonly) ?: throw 
unauthorized()
         val resourceName = call.expectUriComponent("USERNAME")
         if (c.login != resourceName && c.login != "admin") throw forbidden()
         // Collecting params.
@@ -386,34 +354,34 @@ fun Routing.accountsMgmtHandlers(db: Database, ctx: 
BankApplicationContext) {
             ?: throw internalServerError("Customer '${c.login}' lacks bank 
account.")
         val bankAccountId = bankAccount.expectRowId()
         val history: List<BankAccountTransaction> = 
db.bankTransactionGetHistory(
-            start = historyParams.start,
-            delta = historyParams.delta,
-            bankAccountId = bankAccountId
+            start = historyParams.start, delta = historyParams.delta, 
bankAccountId = bankAccountId
         )
         val res = BankAccountTransactionsResponse(transactions = 
mutableListOf())
         history.forEach {
-            res.transactions.add(BankAccountTransactionInfo(
-                debtor_payto_uri = it.debtorPaytoUri,
-                creditor_payto_uri = it.creditorPaytoUri,
-                subject = it.subject,
-                amount = it.amount.toString(),
-                direction = it.direction,
-                date = it.transactionDate,
-                row_id = it.dbRowId ?: throw internalServerError(
-                    "Transaction timestamped with '${it.transactionDate}' did 
not have row ID"
+            res.transactions.add(
+                BankAccountTransactionInfo(
+                    debtor_payto_uri = it.debtorPaytoUri,
+                    creditor_payto_uri = it.creditorPaytoUri,
+                    subject = it.subject,
+                    amount = it.amount.toString(),
+                    direction = it.direction,
+                    date = it.transactionDate,
+                    row_id = it.dbRowId ?: throw internalServerError(
+                        "Transaction timestamped with '${it.transactionDate}' 
did not have row ID"
+                    )
                 )
-            ))
+            )
         }
         call.respond(res)
         return@get
     }
+
     // Creates a bank transaction.
     post("/accounts/{USERNAME}/transactions") {
-        val c = call.myAuth(db, TokenScope.readwrite) ?: throw unauthorized()
+        val c = 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()
+        if ((c.login != resourceName) && (call.getAuthToken() == null)) throw 
forbidden()
         val txData = call.receive<BankAccountTransactionCreate>()
         // FIXME: make payto parser IBAN-agnostic?
         val payto = parsePayto(txData.payto_uri) ?: throw badRequest("Invalid 
creditor Payto")
@@ -422,17 +390,13 @@ fun Routing.accountsMgmtHandlers(db: Database, ctx: 
BankApplicationContext) {
         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 creditorCustomerData = 
db.bankAccountGetFromInternalPayto(paytoWithoutParams)
-            ?: throw notFound(
-                "Creditor account not found",
-                TalerErrorCode.TALER_EC_END // FIXME: define this EC.
-            )
+        val creditorCustomerData = 
db.bankAccountGetFromInternalPayto(paytoWithoutParams) ?: throw notFound(
+            "Creditor account not found", TalerErrorCode.TALER_EC_END // 
FIXME: define this EC.
+        )
         val amount = parseTalerAmount(txData.amount)
-        if (amount.currency != ctx.currency)
-            throw badRequest(
-                "Wrong currency: ${amount.currency}",
-                talerErrorCode = 
TalerErrorCode.TALER_EC_GENERIC_CURRENCY_MISMATCH
-            )
+        if (amount.currency != ctx.currency) throw badRequest(
+            "Wrong currency: ${amount.currency}", talerErrorCode = 
TalerErrorCode.TALER_EC_GENERIC_CURRENCY_MISMATCH
+        )
         val dbInstructions = BankInternalTransaction(
             debtorAccountId = debtorId,
             creditorAccountId = creditorCustomerData.owningCustomerId,
@@ -441,26 +405,25 @@ fun Routing.accountsMgmtHandlers(db: Database, ctx: 
BankApplicationContext) {
             transactionDate = getNowUs()
         )
         val res = db.bankTransactionCreate(dbInstructions)
-        when(res) {
-            Database.BankTransactionResult.CONFLICT ->
-                throw conflict(
-                    "Insufficient funds",
-                    TalerErrorCode.TALER_EC_END // FIXME: need bank 
'insufficient funds' EC.
-                )
-            Database.BankTransactionResult.NO_CREDITOR ->
-                throw internalServerError("Creditor not found despite previous 
checks.")
-            Database.BankTransactionResult.NO_DEBTOR ->
-                throw internalServerError("Debtor not found despite the 
request was authenticated.")
+        when (res) {
+            Database.BankTransactionResult.CONFLICT -> throw conflict(
+                "Insufficient funds", TalerErrorCode.TALER_EC_END // FIXME: 
need bank 'insufficient funds' EC.
+            )
+
+            Database.BankTransactionResult.NO_CREDITOR -> throw 
internalServerError("Creditor not found despite previous checks.")
+
+            Database.BankTransactionResult.NO_DEBTOR -> throw 
internalServerError("Debtor not found despite the request was authenticated.")
+
             Database.BankTransactionResult.SUCCESS -> 
call.respond(HttpStatusCode.OK)
         }
         return@post
     }
+
     get("/accounts/{USERNAME}/transactions/{T_ID}") {
-        val c = call.myAuth(db, TokenScope.readonly) ?: throw unauthorized()
+        val c = call.authenticateBankRequest(db, TokenScope.readonly) ?: throw 
unauthorized()
         val accountOwner = call.expectUriComponent("USERNAME")
         // auth ok, check rights.
-        if (c.login != "admin" && c.login != accountOwner)
-            throw forbidden()
+        if (c.login != "admin" && c.login != accountOwner) throw forbidden()
         // rights ok, check tx exists.
         val tId = call.expectUriComponent("T_ID")
         val txRowId = try {
@@ -470,25 +433,24 @@ fun Routing.accountsMgmtHandlers(db: Database, ctx: 
BankApplicationContext) {
             throw badRequest("TRANSACTION_ID is not a number: ${tId}")
         }
         val customerRowId = c.dbRowId ?: throw 
internalServerError("Authenticated client lacks database entry")
-        val tx = db.bankTransactionGetFromInternalId(txRowId)
-            ?: throw notFound(
-                "Bank transaction '$tId' not found",
-                TalerErrorCode.TALER_EC_NONE // FIXME: need def.
-            )
+        val tx = db.bankTransactionGetFromInternalId(txRowId) ?: throw 
notFound(
+            "Bank transaction '$tId' not found", TalerErrorCode.TALER_EC_NONE 
// FIXME: need def.
+        )
         val customerBankAccount = db.bankAccountGetFromOwnerId(customerRowId)
             ?: throw internalServerError("Customer '${c.login}' lacks bank 
account.")
-        if (tx.bankAccountId != customerBankAccount.bankAccountId)
-            throw forbidden("Client has no rights over the bank transaction: 
$tId")
+        if (tx.bankAccountId != customerBankAccount.bankAccountId) throw 
forbidden("Client has no rights over the bank transaction: $tId")
         // auth and rights, respond.
-        call.respond(BankAccountTransactionInfo(
-            amount = 
"${tx.amount.currency}:${tx.amount.value}.${tx.amount.frac}",
-            creditor_payto_uri = tx.creditorPaytoUri,
-            debtor_payto_uri = tx.debtorPaytoUri,
-            date = tx.transactionDate,
-            direction = tx.direction,
-            subject = tx.subject,
-            row_id = txRowId
-        ))
+        call.respond(
+            BankAccountTransactionInfo(
+                amount = 
"${tx.amount.currency}:${tx.amount.value}.${tx.amount.frac}",
+                creditor_payto_uri = tx.creditorPaytoUri,
+                debtor_payto_uri = tx.debtorPaytoUri,
+                date = tx.transactionDate,
+                direction = tx.direction,
+                subject = tx.subject,
+                row_id = txRowId
+            )
+        )
         return@get
     }
 }
\ No newline at end of file
diff --git a/bank/src/main/kotlin/tech/libeufin/bank/Main.kt 
b/bank/src/main/kotlin/tech/libeufin/bank/Main.kt
index c01fd67f..cb4bb7f9 100644
--- a/bank/src/main/kotlin/tech/libeufin/bank/Main.kt
+++ b/bank/src/main/kotlin/tech/libeufin/bank/Main.kt
@@ -165,38 +165,6 @@ object TalerAmountSerializer : KSerializer<TalerAmount> {
     }
 }
 
-/**
- * This function tries to authenticate the call according
- * to the scheme that is mentioned in the Authorization header.
- * The allowed schemes are either 'HTTP basic auth' or 'bearer token'.
- *
- * requiredScope can be either "readonly" or "readwrite".
- *
- * Returns the authenticated customer, or null if they failed.
- */
-fun ApplicationCall.myAuth(db: Database, requiredScope: TokenScope): Customer? 
{
-    // Extracting the Authorization header.
-    val header = getAuthorizationRawHeader(this.request) ?: throw badRequest(
-        "Authorization header not found.",
-        TalerErrorCode.TALER_EC_GENERIC_HTTP_HEADERS_MALFORMED
-    )
-    val authDetails = getAuthorizationDetails(header) ?: throw badRequest(
-        "Authorization is invalid.",
-        TalerErrorCode.TALER_EC_GENERIC_HTTP_HEADERS_MALFORMED
-    )
-    return when (authDetails.scheme) {
-        "Basic" -> doBasicAuth(db, authDetails.content)
-        "Bearer" -> doTokenAuth(db, authDetails.content, requiredScope)
-        else -> throw LibeufinBankException(
-            httpStatus = HttpStatusCode.Unauthorized,
-            talerError = TalerError(
-                code = TalerErrorCode.TALER_EC_GENERIC_UNAUTHORIZED.code,
-                hint = "Authorization method wrong or not supported."
-            )
-        )
-    }
-}
-
 
 /**
  * Set up web server handlers for the Taler corebank API.
@@ -408,7 +376,7 @@ fun readBankApplicationContextFromConfig(cfg: TalerConfig): 
BankApplicationConte
 
 class ServeBank : CliktCommand("Run libeufin-bank HTTP server", name = 
"serve") {
     private val configFile by option(
-        "--config",
+        "--config", "-c",
         help = "set the configuration file"
     )
     init {
diff --git a/bank/src/main/kotlin/tech/libeufin/bank/WireGatewayApiHandlers.kt 
b/bank/src/main/kotlin/tech/libeufin/bank/WireGatewayApiHandlers.kt
index 619e5fc8..dda207b5 100644
--- a/bank/src/main/kotlin/tech/libeufin/bank/WireGatewayApiHandlers.kt
+++ b/bank/src/main/kotlin/tech/libeufin/bank/WireGatewayApiHandlers.kt
@@ -34,8 +34,9 @@ fun Routing.talerWireGatewayHandlers(db: Database, ctx: 
BankApplicationContext)
         call.respond(TWGConfigResponse(currency = ctx.currency))
         return@get
     }
+
     get("/accounts/{USERNAME}/taler-wire-gateway/history/incoming") {
-        val c = call.myAuth(db, TokenScope.readonly) ?: throw unauthorized()
+        val c = call.authenticateBankRequest(db, TokenScope.readonly) ?: throw 
unauthorized()
         if (!call.getResourceName("USERNAME").canI(c, withAdmin = true)) throw 
forbidden()
         val params = getHistoryParams(call.request)
         val bankAccount = db.bankAccountGetFromOwnerId(c.expectRowId())
@@ -66,8 +67,9 @@ fun Routing.talerWireGatewayHandlers(db: Database, ctx: 
BankApplicationContext)
         call.respond(resp)
         return@get
     }
+
     post("/accounts/{USERNAME}/taler-wire-gateway/transfer") {
-        val c = call.myAuth(db, TokenScope.readwrite) ?: throw unauthorized()
+        val c = call.authenticateBankRequest(db, TokenScope.readwrite) ?: 
throw unauthorized()
         if (!call.getResourceName("USERNAME").canI(c, withAdmin = false)) 
throw forbidden()
         val req = call.receive<TransferRequest>()
         // Checking for idempotency.
@@ -120,8 +122,9 @@ fun Routing.talerWireGatewayHandlers(db: Database, ctx: 
BankApplicationContext)
         ))
         return@post
     }
+
     post("/accounts/{USERNAME}/taler-wire-gateway/admin/add-incoming") {
-        val c = call.myAuth(db, TokenScope.readwrite) ?: throw unauthorized()
+        val c = call.authenticateBankRequest(db, TokenScope.readwrite) ?: 
throw unauthorized()
         if (!call.getResourceName("USERNAME").canI(c, withAdmin = false)) 
throw forbidden()
         val req = call.receive<AddIncomingRequest>()
         val amount = parseTalerAmount(req.amount)
diff --git a/bank/src/main/kotlin/tech/libeufin/bank/helpers.kt 
b/bank/src/main/kotlin/tech/libeufin/bank/helpers.kt
index dd7d8027..9969f32c 100644
--- a/bank/src/main/kotlin/tech/libeufin/bank/helpers.kt
+++ b/bank/src/main/kotlin/tech/libeufin/bank/helpers.kt
@@ -20,7 +20,6 @@
 package tech.libeufin.bank
 
 import io.ktor.http.*
-import io.ktor.http.cio.*
 import io.ktor.server.application.*
 import io.ktor.server.plugins.*
 import io.ktor.server.request.*
@@ -30,10 +29,8 @@ import net.taler.wallet.crypto.Base32Crockford
 import org.slf4j.Logger
 import org.slf4j.LoggerFactory
 import tech.libeufin.util.*
-import java.lang.NumberFormatException
 import java.net.URL
 import java.util.*
-import kotlin.system.exitProcess
 
 const val FRACTION_BASE = 100000000
 
@@ -41,23 +38,20 @@ private val logger: Logger = 
LoggerFactory.getLogger("tech.libeufin.bank.helpers
 
 fun ApplicationCall.expectUriComponent(componentName: String) =
     this.maybeUriComponent(componentName) ?: throw badRequest(
-        hint = "No username found in the URI",
-        talerErrorCode = TalerErrorCode.TALER_EC_GENERIC_PARAMETER_MISSING
-)
+        hint = "No username found in the URI", talerErrorCode = 
TalerErrorCode.TALER_EC_GENERIC_PARAMETER_MISSING
+    )
+
 // Get the auth token (stripped of the bearer-token:-prefix)
 // IF the call was authenticated with it.
 fun ApplicationCall.getAuthToken(): String? {
     val h = getAuthorizationRawHeader(this.request) ?: return null
     val authDetails = getAuthorizationDetails(h) ?: throw badRequest(
-        "Authorization header is malformed.",
+        "Authorization header is malformed.", 
TalerErrorCode.TALER_EC_GENERIC_HTTP_HEADERS_MALFORMED
+    )
+    if (authDetails.scheme == "Bearer") return 
splitBearerToken(authDetails.content) ?: throw throw badRequest(
+        "Authorization header is malformed (could not strip the prefix from 
Bearer token).",
         TalerErrorCode.TALER_EC_GENERIC_HTTP_HEADERS_MALFORMED
     )
-    if (authDetails.scheme == "Bearer")
-        return splitBearerToken(authDetails.content) ?: throw
-        throw badRequest(
-            "Authorization header is malformed (could not strip the prefix 
from Bearer token).",
-            TalerErrorCode.TALER_EC_GENERIC_HTTP_HEADERS_MALFORMED
-        )
     return null // Not a Bearer token case.
 }
 
@@ -76,14 +70,12 @@ fun doBasicAuth(db: Database, encodedCredentials: String): 
Customer? {
          */
         limit = 2
     )
-    if (userAndPassSplit.size != 2)
-        throw LibeufinBankException(
-            httpStatus = HttpStatusCode.BadRequest,
-            talerError = TalerError(
-                code = 
TalerErrorCode.TALER_EC_GENERIC_HTTP_HEADERS_MALFORMED.code,
-                "Malformed Basic auth credentials found in the Authorization 
header."
-            )
+    if (userAndPassSplit.size != 2) throw LibeufinBankException(
+        httpStatus = HttpStatusCode.BadRequest, talerError = TalerError(
+            code = TalerErrorCode.TALER_EC_GENERIC_HTTP_HEADERS_MALFORMED.code,
+            "Malformed Basic auth credentials found in the Authorization 
header."
         )
+    )
     val login = userAndPassSplit[0]
     val plainPassword = userAndPassSplit[1]
     val maybeCustomer = db.customerGetFromLogin(login) ?: throw unauthorized()
@@ -111,15 +103,13 @@ fun doTokenAuth(
     requiredScope: TokenScope,
 ): Customer? {
     val bareToken = splitBearerToken(token) ?: throw badRequest(
-        "Bearer token malformed",
-        talerErrorCode = TalerErrorCode.TALER_EC_GENERIC_HTTP_HEADERS_MALFORMED
+        "Bearer token malformed", talerErrorCode = 
TalerErrorCode.TALER_EC_GENERIC_HTTP_HEADERS_MALFORMED
     )
     val tokenBytes = try {
         Base32Crockford.decode(bareToken)
     } catch (e: Exception) {
         throw badRequest(
-            e.message,
-            TalerErrorCode.TALER_EC_GENERIC_HTTP_HEADERS_MALFORMED
+            e.message, TalerErrorCode.TALER_EC_GENERIC_HTTP_HEADERS_MALFORMED
         )
     }
     val maybeToken: BearerToken? = db.bearerTokenGet(tokenBytes)
@@ -140,87 +130,67 @@ fun doTokenAuth(
         return null
     }
     // Getting the related username.
-    return db.customerGetFromRowId(maybeToken.bankCustomer)
-        ?: throw LibeufinBankException(
-            httpStatus = HttpStatusCode.InternalServerError,
-            talerError = TalerError(
-                code = 
TalerErrorCode.TALER_EC_GENERIC_INTERNAL_INVARIANT_FAILURE.code,
-                hint = "Customer not found, despite token mentions it.",
-            ))
+    return db.customerGetFromRowId(maybeToken.bankCustomer) ?: throw 
LibeufinBankException(
+        httpStatus = HttpStatusCode.InternalServerError, talerError = 
TalerError(
+            code = 
TalerErrorCode.TALER_EC_GENERIC_INTERNAL_INVARIANT_FAILURE.code,
+            hint = "Customer not found, despite token mentions it.",
+        )
+    )
 }
 
 fun forbidden(
     hint: String = "No rights on the resource",
     // FIXME: create a 'generic forbidden' Taler EC.
     talerErrorCode: TalerErrorCode = TalerErrorCode.TALER_EC_END
-): LibeufinBankException =
-    LibeufinBankException(
-        httpStatus = HttpStatusCode.Forbidden,
-        talerError = TalerError(
-            code = talerErrorCode.code,
-            hint = hint
-        )
+): LibeufinBankException = LibeufinBankException(
+    httpStatus = HttpStatusCode.Forbidden, talerError = TalerError(
+        code = talerErrorCode.code, hint = hint
     )
+)
 
-fun unauthorized(hint: String = "Login failed"): LibeufinBankException =
-    LibeufinBankException(
-        httpStatus = HttpStatusCode.Unauthorized,
-        talerError = TalerError(
-            code = TalerErrorCode.TALER_EC_BANK_LOGIN_FAILED.code,
-            hint = hint
-        )
+fun unauthorized(hint: String = "Login failed"): LibeufinBankException = 
LibeufinBankException(
+    httpStatus = HttpStatusCode.Unauthorized, talerError = TalerError(
+        code = TalerErrorCode.TALER_EC_BANK_LOGIN_FAILED.code, hint = hint
     )
-fun internalServerError(hint: String?): LibeufinBankException =
-    LibeufinBankException(
-        httpStatus = HttpStatusCode.InternalServerError,
-        talerError = TalerError(
-            code = 
TalerErrorCode.TALER_EC_GENERIC_INTERNAL_INVARIANT_FAILURE.code,
-            hint = hint
-        )
+)
+
+fun internalServerError(hint: String?): LibeufinBankException = 
LibeufinBankException(
+    httpStatus = HttpStatusCode.InternalServerError, talerError = TalerError(
+        code = 
TalerErrorCode.TALER_EC_GENERIC_INTERNAL_INVARIANT_FAILURE.code, hint = hint
     )
+)
 
 
 fun notFound(
-    hint: String?,
-    talerEc: TalerErrorCode
-): LibeufinBankException =
-    LibeufinBankException(
-        httpStatus = HttpStatusCode.NotFound,
-        talerError = TalerError(
-            code = talerEc.code,
-            hint = hint
-        )
+    hint: String?, talerEc: TalerErrorCode
+): LibeufinBankException = LibeufinBankException(
+    httpStatus = HttpStatusCode.NotFound, talerError = TalerError(
+        code = talerEc.code, hint = hint
     )
+)
 
 fun conflict(
-    hint: String?,
-    talerEc: TalerErrorCode
-): LibeufinBankException =
-    LibeufinBankException(
-        httpStatus = HttpStatusCode.Conflict,
-        talerError = TalerError(
-            code = talerEc.code,
-            hint = hint
-        )
+    hint: String?, talerEc: TalerErrorCode
+): LibeufinBankException = LibeufinBankException(
+    httpStatus = HttpStatusCode.Conflict, talerError = TalerError(
+        code = talerEc.code, hint = hint
     )
+)
+
 fun badRequest(
-    hint: String? = null,
-    talerErrorCode: TalerErrorCode = 
TalerErrorCode.TALER_EC_GENERIC_JSON_INVALID
-): LibeufinBankException =
-    LibeufinBankException(
-        httpStatus = HttpStatusCode.BadRequest,
-        talerError = TalerError(
-            code = talerErrorCode.code,
-            hint = hint
-        )
+    hint: String? = null, talerErrorCode: TalerErrorCode = 
TalerErrorCode.TALER_EC_GENERIC_JSON_INVALID
+): LibeufinBankException = LibeufinBankException(
+    httpStatus = HttpStatusCode.BadRequest, talerError = TalerError(
+        code = talerErrorCode.code, hint = hint
     )
+)
+
 // Generates a new Payto-URI with IBAN scheme.
 fun genIbanPaytoUri(): String = "payto://iban/SANDBOXX/${getIban()}"
 
 // Parses Taler amount, returning null if the input is invalid.
 fun parseTalerAmount2(
-    amount: String,
-    fracDigits: FracDigits
+    amount: String, fracDigits: FracDigits
 ): TalerAmount? {
     val format = when (fracDigits) {
         FracDigits.TWO -> "^([A-Z]+):([0-9]+)(\\.[0-9][0-9]?)?$"
@@ -246,11 +216,10 @@ fun parseTalerAmount2(
         return null
     }
     return TalerAmount(
-        value = value,
-        frac = fraction,
-        currency = match.destructured.component1()
+        value = value, frac = fraction, currency = 
match.destructured.component1()
     )
 }
+
 /**
  * This helper takes the serialized version of a Taler Amount
  * type and parses it into Libeufin's internal representation.
@@ -260,16 +229,13 @@ fun parseTalerAmount2(
  * responded to the client.
  */
 fun parseTalerAmount(
-    amount: String,
-    fracDigits: FracDigits = FracDigits.EIGHT
+    amount: String, fracDigits: FracDigits = FracDigits.EIGHT
 ): TalerAmount {
-    val maybeAmount = parseTalerAmount2(amount, fracDigits)
-        ?: throw LibeufinBankException(
-            httpStatus = HttpStatusCode.BadRequest,
-            talerError = TalerError(
-                code = TalerErrorCode.TALER_EC_BANK_BAD_FORMAT_AMOUNT.code,
-                hint = "Invalid amount: $amount"
-            ))
+    val maybeAmount = parseTalerAmount2(amount, fracDigits) ?: throw 
LibeufinBankException(
+        httpStatus = HttpStatusCode.BadRequest, talerError = TalerError(
+            code = TalerErrorCode.TALER_EC_BANK_BAD_FORMAT_AMOUNT.code, hint = 
"Invalid amount: $amount"
+        )
+    )
     return maybeAmount
 }
 
@@ -278,9 +244,7 @@ private fun normalizeAmount(amt: TalerAmount): TalerAmount {
         val normalValue = amt.value + (amt.frac / FRACTION_BASE)
         val normalFrac = amt.frac % FRACTION_BASE
         return TalerAmount(
-            value = normalValue,
-            frac = normalFrac,
-            currency = amt.currency
+            value = normalValue, frac = normalFrac, currency = amt.currency
         )
     }
     return amt
@@ -289,22 +253,19 @@ private fun normalizeAmount(amt: TalerAmount): 
TalerAmount {
 
 // Adds two amounts and returns the normalized version.
 private fun amountAdd(first: TalerAmount, second: TalerAmount): TalerAmount {
-    if (first.currency != second.currency)
-        throw badRequest(
-            "Currency mismatch, balance '${first.currency}', price 
'${second.currency}'",
-            TalerErrorCode.TALER_EC_GENERIC_CURRENCY_MISMATCH
-        )
+    if (first.currency != second.currency) throw badRequest(
+        "Currency mismatch, balance '${first.currency}', price 
'${second.currency}'",
+        TalerErrorCode.TALER_EC_GENERIC_CURRENCY_MISMATCH
+    )
     val valueAdd = first.value + second.value
-    if (valueAdd < first.value)
-        throw badRequest("Amount value overflowed")
+    if (valueAdd < first.value) throw badRequest("Amount value overflowed")
     val fracAdd = first.frac + second.frac
-    if (fracAdd < first.frac)
-        throw badRequest("Amount fraction overflowed")
-    return normalizeAmount(TalerAmount(
-        value = valueAdd,
-        frac = fracAdd,
-        currency = first.currency
-    ))
+    if (fracAdd < first.frac) throw badRequest("Amount fraction overflowed")
+    return normalizeAmount(
+        TalerAmount(
+            value = valueAdd, frac = fracAdd, currency = first.currency
+        )
+    )
 }
 
 /**
@@ -315,20 +276,13 @@ private fun amountAdd(first: TalerAmount, second: 
TalerAmount): TalerAmount {
  * the database.
  */
 fun isBalanceEnough(
-    balance: TalerAmount,
-    due: TalerAmount,
-    maxDebt: TalerAmount,
-    hasBalanceDebt: Boolean
+    balance: TalerAmount, due: TalerAmount, maxDebt: TalerAmount, 
hasBalanceDebt: Boolean
 ): Boolean {
     val normalMaxDebt = normalizeAmount(maxDebt) // Very unlikely to be needed.
     if (hasBalanceDebt) {
         val chargedBalance = amountAdd(balance, due)
         if (chargedBalance.value > normalMaxDebt.value) return false // max 
debt surpassed
-        if (
-            (chargedBalance.value == normalMaxDebt.value) &&
-            (chargedBalance.frac > maxDebt.frac)
-            )
-            return false
+        if ((chargedBalance.value == normalMaxDebt.value) && 
(chargedBalance.frac > maxDebt.frac)) return false
         return true
     }
     /**
@@ -336,19 +290,17 @@ fun isBalanceEnough(
      * block calculates how much debt the balance would get, should a
      * subtraction of 'due' occur.
      */
-    if (balance.currency != due.currency)
-        throw badRequest(
-            "Currency mismatch, balance '${balance.currency}', due 
'${due.currency}'",
-            TalerErrorCode.TALER_EC_GENERIC_CURRENCY_MISMATCH
-        )
+    if (balance.currency != due.currency) throw badRequest(
+        "Currency mismatch, balance '${balance.currency}', due 
'${due.currency}'",
+        TalerErrorCode.TALER_EC_GENERIC_CURRENCY_MISMATCH
+    )
     val valueDiff = if (balance.value < due.value) due.value - balance.value 
else 0L
     val fracDiff = if (balance.frac < due.frac) due.frac - balance.frac else 0
     // Getting the normalized version of such diff.
     val normalDiff = normalizeAmount(TalerAmount(valueDiff, fracDiff, 
balance.currency))
     // Failing if the normalized diff surpasses the max debt.
     if (normalDiff.value > normalMaxDebt.value) return false
-    if ((normalDiff.value == normalMaxDebt.value) &&
-        (normalDiff.frac > normalMaxDebt.frac)) return false
+    if ((normalDiff.value == normalMaxDebt.value) && (normalDiff.frac > 
normalMaxDebt.frac)) return false
     return true
 }
 
@@ -360,47 +312,41 @@ fun isBalanceEnough(
  *
  *      https://$BANK_URL/taler-integration
  */
-fun getTalerWithdrawUri(baseUrl: String, woId: String) =
-    url {
-        val baseUrlObj = URL(baseUrl)
-        protocol = URLProtocol(
-            name = "taler".plus(if (baseUrlObj.protocol.lowercase() == "http") 
"+http" else ""),
-            defaultPort = -1
-        )
-        host = "withdraw"
-        val pathSegments = mutableListOf(
-            // adds the hostname(+port) of the actual bank that will serve the 
withdrawal request.
-            baseUrlObj.host.plus(
-                if (baseUrlObj.port != -1)
-                    ":${baseUrlObj.port}"
-                else ""
-            )
+fun getTalerWithdrawUri(baseUrl: String, woId: String) = url {
+    val baseUrlObj = URL(baseUrl)
+    protocol = URLProtocol(
+        name = "taler".plus(if (baseUrlObj.protocol.lowercase() == "http") 
"+http" else ""), defaultPort = -1
+    )
+    host = "withdraw"
+    val pathSegments = mutableListOf(
+        // adds the hostname(+port) of the actual bank that will serve the 
withdrawal request.
+        baseUrlObj.host.plus(
+            if (baseUrlObj.port != -1) ":${baseUrlObj.port}"
+            else ""
         )
-        // Removing potential double slashes.
-        baseUrlObj.path.split("/").forEach {
-            if (it.isNotEmpty()) pathSegments.add(it)
-        }
-        pathSegments.add("taler-integration/${woId}")
-        this.appendPathSegments(pathSegments)
+    )
+    // Removing potential double slashes.
+    baseUrlObj.path.split("/").forEach {
+        if (it.isNotEmpty()) pathSegments.add(it)
     }
+    pathSegments.add("taler-integration/${woId}")
+    this.appendPathSegments(pathSegments)
+}
 
 // Builds a withdrawal confirm URL.
 fun getWithdrawalConfirmUrl(
-    baseUrl: String,
-    wopId: String,
-    username: 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("accounts/${username}/withdrawals/${wopId}/confirm")
+    baseUrl: String, wopId: String, username: 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("accounts/${username}/withdrawals/${wopId}/confirm")
+}
 
 
 /**
@@ -417,24 +363,23 @@ fun getWithdrawal(db: Database, opIdParam: String): 
TalerWithdrawalOperation {
         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
-        )
+    val op = db.talerWithdrawalGet(opId) ?: throw notFound(
+        hint = "Withdrawal operation $opIdParam not found", talerEc = 
TalerErrorCode.TALER_EC_END
+    )
     return op
 }
 
 data class HistoryParams(
-    val delta: Long,
-    val start: Long
+    val delta: Long, val start: Long
 )
+
 /**
  * Extracts the query parameters from "history-like" endpoints,
  * providing the defaults according to the API specification.
  */
 fun getHistoryParams(req: ApplicationRequest): HistoryParams {
-    val deltaParam: String = req.queryParameters["delta"] ?: throw 
MissingRequestParameterException(parameterName = "delta")
+    val deltaParam: String =
+        req.queryParameters["delta"] ?: throw 
MissingRequestParameterException(parameterName = "delta")
     val delta: Long = try {
         deltaParam.toLong()
     } catch (e: Exception) {
@@ -473,8 +418,7 @@ fun maybeCreateAdminAccount(db: Database, ctx: 
BankApplicationContext): Boolean
              * Hashing the password helps to avoid the "password not hashed"
              * error, in case the admin tries to authenticate.
              */
-            passwordHash = CryptoUtil.hashpw(String(pwBuf, Charsets.UTF_8)),
-            name = "Bank administrator"
+            passwordHash = CryptoUtil.hashpw(String(pwBuf, Charsets.UTF_8)), 
name = "Bank administrator"
         )
         val rowId = db.customerCreate(adminCustomer)
         if (rowId == null) {
@@ -482,9 +426,7 @@ fun maybeCreateAdminAccount(db: Database, ctx: 
BankApplicationContext): Boolean
             return false
         }
         rowId
-    }
-    else
-        maybeAdminCustomer.expectRowId()
+    } else maybeAdminCustomer.expectRowId()
     val maybeAdminBankAccount = db.bankAccountGetFromOwnerId(adminCustomerId)
     if (maybeAdminBankAccount == null) {
         logger.info("Creating admin bank account")
diff --git a/contrib/libeufin-bank.sample.conf 
b/contrib/libeufin-bank.sample.conf
index a50fef97..00317b8e 100644
--- a/contrib/libeufin-bank.sample.conf
+++ b/contrib/libeufin-bank.sample.conf
@@ -1,5 +1,5 @@
 [libeufin-bank]
-currency = KUDOS
+CURRENCY = KUDOS
 DEFAULT_CUSTOMER_DEBT_LIMIT = KUDOS:200
 DEFAULT_ADMIN_DEBT_LIMIT = KUDOS:2000
 REGISTRATION_BONUS = KUDOS:100
diff --git a/util/src/main/kotlin/HTTP.kt b/util/src/main/kotlin/HTTP.kt
index ac3a51bc..b1e0fc02 100644
--- a/util/src/main/kotlin/HTTP.kt
+++ b/util/src/main/kotlin/HTTP.kt
@@ -3,9 +3,7 @@ package tech.libeufin.util
 import io.ktor.http.*
 import io.ktor.server.application.*
 import io.ktor.server.request.*
-import io.ktor.server.response.*
 import io.ktor.server.util.*
-import io.ktor.util.*
 import logger
 
 // Get the base URL of a request, returns null if any problem occurs.
@@ -22,13 +20,13 @@ fun ApplicationRequest.getBaseUrl(): String? {
             prefix += "/"
         URLBuilder(
             protocol = URLProtocol(
-                name = this.headers.get("X-Forwarded-Proto") ?: run {
+                name = this.headers["X-Forwarded-Proto"] ?: run {
                     logger.error("Reverse proxy did not define 
X-Forwarded-Proto")
                     return null
                 },
                 defaultPort = -1 // Port must be specified with 
X-Forwarded-Host.
             ),
-            host = this.headers.get("X-Forwarded-Host") ?: run {
+            host = this.headers["X-Forwarded-Host"] ?: run {
                 logger.error("Reverse proxy did not define X-Forwarded-Host")
                 return null
             }
@@ -46,10 +44,6 @@ fun ApplicationRequest.getBaseUrl(): String? {
     }
 }
 
-/**
- * Get the URI (path's) component or throw Internal server error.
- * @param component the name of the URI component to return.
- */
 fun ApplicationCall.maybeUriComponent(name: String): String? {
     val ret: String? = this.parameters[name]
     if (ret == null) {
@@ -77,6 +71,7 @@ data class AuthorizationDetails(
     val scheme: String,
     val content: String
 )
+
 // Returns the authorization scheme mentioned in the Auth header,
 // or null if that could not be found.
 fun getAuthorizationDetails(authorizationHeader: String): 
AuthorizationDetails? {

-- 
To stop receiving notification emails like this one, please contact
gnunet@gnunet.org.



reply via email to

[Prev in Thread] Current Thread [Next in Thread]