gnunet-svn
[Top][All Lists]
Advanced

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

[libeufin] branch master updated: read configuration from file, remove c


From: gnunet
Subject: [libeufin] branch master updated: read configuration from file, remove config from DB
Date: Fri, 22 Sep 2023 17:13:45 +0200

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

dold pushed a commit to branch master
in repository libeufin.

The following commit(s) were added to refs/heads/master by this push:
     new e5c64e7b read configuration from file, remove config from DB
e5c64e7b is described below

commit e5c64e7b494d19e7ebdc4124fc17cdd9d104715a
Author: Florian Dold <florian@dold.me>
AuthorDate: Fri Sep 22 17:13:48 2023 +0200

    read configuration from file, remove config from DB
---
 .../src/main/kotlin/tech/libeufin/bank/Database.kt |  43 +----
 bank/src/main/kotlin/tech/libeufin/bank/Main.kt    | 148 +++++++++++++++--
 .../tech/libeufin/bank/accountsMgmtHandlers.kt     |  25 +--
 bank/src/main/kotlin/tech/libeufin/bank/helpers.kt |  27 +--
 .../tech/libeufin/bank/talerIntegrationHandlers.kt |  11 +-
 .../tech/libeufin/bank/talerWireGatewayHandlers.kt |  12 +-
 .../kotlin/tech/libeufin/bank/tokenHandlers.kt     |  17 +-
 .../tech/libeufin/bank/transactionsHandlers.kt     |   4 +-
 bank/src/main/kotlin/tech/libeufin/bank/types.kt   |  26 +--
 bank/src/test/kotlin/AmountTest.kt                 |  10 --
 bank/src/test/kotlin/Common.kt                     |  23 ++-
 bank/src/test/kotlin/DatabaseTest.kt               |  15 +-
 bank/src/test/kotlin/LibeuFinApiTest.kt            | 181 +++++++++++++--------
 bank/src/test/kotlin/TalerApiTest.kt               |  32 ++--
 contrib/wallet-core                                |   2 +-
 database-versioning/libeufin-bank-0001.sql         |   9 -
 util/src/main/kotlin/TalerConfig.kt                |  21 ++-
 util/src/test/kotlin/TalerConfigTest.kt            |   2 +-
 18 files changed, 355 insertions(+), 253 deletions(-)

diff --git a/bank/src/main/kotlin/tech/libeufin/bank/Database.kt 
b/bank/src/main/kotlin/tech/libeufin/bank/Database.kt
index d5789396..e280e0ed 100644
--- a/bank/src/main/kotlin/tech/libeufin/bank/Database.kt
+++ b/bank/src/main/kotlin/tech/libeufin/bank/Database.kt
@@ -40,11 +40,10 @@ fun BankAccountTransaction.expectRowId(): Long = 
this.dbRowId ?: throw internalS
 private val logger: Logger = 
LoggerFactory.getLogger("tech.libeufin.bank.Database")
 
 
-class Database(private val dbConfig: String) {
+class Database(private val dbConfig: String, private val bankCurrency: String) 
{
     private var dbConn: PgConnection? = null
     private var dbCtr: Int = 0
     private val preparedStatements: MutableMap<String, PreparedStatement> = 
mutableMapOf()
-    private var cachedCurrency: String? = null;
 
     init {
         Class.forName("org.postgresql.Driver")
@@ -90,42 +89,6 @@ class Database(private val dbConfig: String) {
         return true
     }
 
-    /**
-     * Get the currency applicable to the bank.
-     */
-    private fun getCurrency(): String {
-        var myCurrency = cachedCurrency
-        if (myCurrency != null) {
-            return myCurrency
-        }
-        // FIXME: Should be retrieved from the config file instead of the DB.
-        myCurrency = configGet("internal_currency")
-        if (myCurrency == null) {
-            throw Error("configuration does not specify currency")
-        }
-        cachedCurrency = myCurrency
-        return myCurrency
-    }
-
-    // CONFIG
-    fun configGet(configKey: String): String? {
-        reconnect()
-        val stmt = prepare("SELECT config_value FROM configuration WHERE 
config_key=?;")
-        stmt.setString(1, configKey)
-        val rs = stmt.executeQuery()
-        rs.use {
-            if(!it.next()) return null
-            return it.getString("config_value")
-        }
-    }
-    fun configSet(configKey: String, configValue: String) {
-        reconnect()
-        val stmt = prepare("CALL bank_set_config(TEXT(?), TEXT(?))")
-        stmt.setString(1, configKey)
-        stmt.setString(2, configValue)
-        stmt.execute()
-    }
-
     // CUSTOMERS
     /**
      * This method INSERTs a new customer into the database and
@@ -353,6 +316,10 @@ class Database(private val dbConfig: String) {
         return myExecute(stmt)
     }
 
+    private fun getCurrency(): String {
+        return bankCurrency
+    }
+
     fun bankAccountGetFromOwnerId(ownerId: Long): BankAccount? {
         reconnect()
         val stmt = prepare("""
diff --git a/bank/src/main/kotlin/tech/libeufin/bank/Main.kt 
b/bank/src/main/kotlin/tech/libeufin/bank/Main.kt
index 1e50d855..d04c3816 100644
--- a/bank/src/main/kotlin/tech/libeufin/bank/Main.kt
+++ b/bank/src/main/kotlin/tech/libeufin/bank/Main.kt
@@ -21,6 +21,7 @@
 package tech.libeufin.bank
 
 import TalerConfig
+import TalerConfigError
 import com.github.ajalt.clikt.core.CliktCommand
 import com.github.ajalt.clikt.core.context
 import com.github.ajalt.clikt.core.subcommands
@@ -47,13 +48,11 @@ import kotlinx.serialization.encoding.Encoder
 import kotlinx.serialization.json.*
 import kotlinx.serialization.modules.SerializersModule
 import net.taler.common.errorcodes.TalerErrorCode
-import net.taler.wallet.crypto.Base32Crockford
 import org.slf4j.Logger
 import org.slf4j.LoggerFactory
 import org.slf4j.event.Level
 import tech.libeufin.util.*
 import java.time.Duration
-import java.util.Random
 import kotlin.system.exitProcess
 
 // GLOBALS
@@ -62,6 +61,50 @@ const val GENERIC_UNDEFINED = -1 // Filler for ECs that 
don't exist yet.
 val TOKEN_DEFAULT_DURATION_US = Duration.ofDays(1L).seconds * 1000000
 
 
+/**
+ * Application context with the parsed configuration.
+ */
+data class BankApplicationContext(
+    /**
+     * Main, internal currency of the bank.
+     */
+    val currency: String,
+    /**
+     * Restrict account registration to the administrator.
+     */
+    val restrictRegistration: Boolean,
+    /**
+     * Cashout currency, if cashouts are supported.
+     */
+    val cashoutCurrency: String?,
+    /**
+     * Default limit for the debt that a customer can have.
+     * Can be adjusted per account after account creation.
+     */
+    val defaultCustomerDebtLimit: TalerAmount,
+    /**
+     * Debt limit of the admin account.
+     */
+    val defaultAdminDebtLimit: TalerAmount,
+    /**
+     * If true, transfer a registration bonus from the admin
+     * account to the newly created account.
+     */
+    val registrationBonusEnabled: Boolean,
+    /**
+     * Only set if registration bonus is enabled.
+     */
+    val registrationBonus: TalerAmount?,
+    /**
+     * Exchange that the bank suggests to wallets for withdrawal.
+     */
+    val suggestedWithdrawalExchange: String?,
+    /**
+     * Max token duration in microseconds.
+     */
+    val maxAuthTokenDurationUs: Long,
+)
+
 /**
  * This custom (de)serializer interprets the RelativeTime JSON
  * type.  In particular, it is responsible for converting the
@@ -157,7 +200,7 @@ fun ApplicationCall.myAuth(db: Database, requiredScope: 
TokenScope): Customer? {
 /**
  * Set up web server handlers for the Taler corebank API.
  */
-fun Application.corebankWebApp(db: Database) {
+fun Application.corebankWebApp(db: Database, ctx: BankApplicationContext) {
     install(CallLogging) {
         this.level = Level.DEBUG
         this.logger = tech.libeufin.bank.logger
@@ -266,12 +309,12 @@ fun Application.corebankWebApp(db: Database) {
             call.respond(Config())
             return@get
         }
-        this.accountsMgmtHandlers(db)
-        this.tokenHandlers(db)
-        this.transactionsHandlers(db)
+        this.accountsMgmtHandlers(db, ctx)
+        this.tokenHandlers(db, ctx)
+        this.transactionsHandlers(db, ctx)
         this.talerWebHandlers(db)
-        this.talerIntegrationHandlers(db)
-        this.talerWireGatewayHandlers(db)
+        this.talerIntegrationHandlers(db, ctx)
+        this.talerWireGatewayHandlers(db, ctx)
     }
 }
 
@@ -283,6 +326,88 @@ class LibeufinBankCommand : CliktCommand() {
     override fun run() = Unit
 }
 
+fun durationFromPretty(s: String): Long {
+    var durationUs: Long = 0;
+    var currentNum = "";
+    var parsingNum = true
+    for (c in s) {
+        if (c >= '0' && c <= '9') {
+            if (!parsingNum) {
+                throw Error("invalid duration, unexpected number")
+            }
+            currentNum += c
+            continue
+        }
+        if (c == ' ') {
+            if (currentNum != "") {
+                parsingNum = false
+            }
+            continue
+        }
+        if (currentNum == "") {
+            throw Error("invalid duration, missing number")
+        }
+        val n = currentNum.toInt(10)
+        durationUs += when (c) {
+            's' -> { n * 1000000 }
+            'm' -> { n * 1000000 * 60 }
+            'h' -> { n * 1000000 * 60 * 60 }
+            'd' -> { n * 1000000 * 60 * 60 * 24 }
+            else -> { throw Error("invalid duration, unsupported unit '$c'") }
+        }
+        parsingNum = true
+        currentNum = ""
+    }
+    return durationUs
+}
+
+/**
+ * FIXME: Introduce a datatype for this instead of using Long
+ */
+fun TalerConfig.requireValueDuration(section: String, option: String): Long {
+    val durationStr = lookupValueString(section, option)
+    if (durationStr == null) {
+        throw TalerConfigError("expected amount for section $section, option 
$option, but config value is empty")
+    }
+    return durationFromPretty(durationStr)
+}
+
+fun TalerConfig.requireValueAmount(section: String, option: String, currency: 
String): TalerAmount {
+    val amountStr = lookupValueString(section, option)
+    if (amountStr == null) {
+        throw TalerConfigError("expected amount for section $section, option 
$option, but config value is empty")
+    }
+    val amount = parseTalerAmount2(amountStr, FracDigits.EIGHT)
+    if (amount == null) {
+        throw TalerConfigError("expected amount for section $section, option 
$option, but amount is malformed")
+    }
+    if (amount.currency != currency) {
+        throw TalerConfigError(
+            "expected amount for section $section, option $option, but 
currency is wrong (got ${amount.currency} expected $currency"
+        )
+    }
+    return amount
+}
+
+/**
+ * Read the configuration of the bank from a config file.
+ * Throws an exception if the configuration is malformed.
+ */
+fun readBankApplicationContextFromConfig(cfg: TalerConfig): 
BankApplicationContext {
+    val currency = cfg.requireValueString("libeufin-bank", "currency")
+    return BankApplicationContext(
+        currency = currency,
+        restrictRegistration = cfg.lookupValueBooleanDefault("libeufin-bank", 
"restrict_registration", false),
+        cashoutCurrency = cfg.lookupValueString("libeufin-bank", 
"cashout_currency"),
+        defaultCustomerDebtLimit = cfg.requireValueAmount("libeufin-bank", 
"default_customer_debt_limit", currency),
+        registrationBonusEnabled = 
cfg.lookupValueBooleanDefault("libeufin-bank", "registration_bonus_enabled", 
false),
+        registrationBonus = cfg.requireValueAmount("libeufin-bank", 
"registration_bonus", currency),
+        suggestedWithdrawalExchange = cfg.lookupValueString("libeufin-bank", 
"suggested_withdrawal_exchange"),
+        defaultAdminDebtLimit = cfg.requireValueAmount("libeufin-bank", 
"default_admin_debt_limit", currency),
+        maxAuthTokenDurationUs = cfg.requireValueDuration("libeufin-bank", 
"max_auth_token_duration"),
+    )
+}
+
 class ServeBank : CliktCommand("Run libeufin-bank HTTP server", name = 
"serve") {
     init {
         context {
@@ -292,13 +417,14 @@ class ServeBank : CliktCommand("Run libeufin-bank HTTP 
server", name = "serve")
 
     override fun run() {
         val config = TalerConfig.load()
+        val ctx = readBankApplicationContextFromConfig(config)
         val dbConnStr = config.requireValueString("libeufin-bank-db-postgres", 
"config")
         logger.info("using database '$dbConnStr'")
-        val db = Database(dbConnStr)
-        if (!maybeCreateAdminAccount(db)) // logs provided by the helper
+        val db = Database(dbConnStr, ctx.currency)
+        if (!maybeCreateAdminAccount(db, ctx)) // logs provided by the helper
             exitProcess(1)
         embeddedServer(Netty, port = 8080) {
-            corebankWebApp(db)
+            corebankWebApp(db, ctx)
         }.start(wait = true)
     }
 }
diff --git a/bank/src/main/kotlin/tech/libeufin/bank/accountsMgmtHandlers.kt 
b/bank/src/main/kotlin/tech/libeufin/bank/accountsMgmtHandlers.kt
index e1890b3f..ef6d66e3 100644
--- a/bank/src/main/kotlin/tech/libeufin/bank/accountsMgmtHandlers.kt
+++ b/bank/src/main/kotlin/tech/libeufin/bank/accountsMgmtHandlers.kt
@@ -19,11 +19,10 @@ private val logger: Logger = 
LoggerFactory.getLogger("tech.libeufin.bank.account
  * create, update, delete, show bank accounts.  No histories
  * and wire transfers should belong here.
  */
-fun Routing.accountsMgmtHandlers(db: Database) {
+fun Routing.accountsMgmtHandlers(db: Database, ctx: BankApplicationContext) {
     post("/accounts") {
-        // check if only admin.
-        val maybeOnlyAdmin = db.configGet("only_admin_registrations")
-        if (maybeOnlyAdmin?.lowercase() == "yes") {
+        // 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(
@@ -84,7 +83,7 @@ fun Routing.accountsMgmtHandlers(db: Database) {
             phone = req.challenge_contact_data?.phone,
             cashoutPayto = req.cashout_payto_uri,
             // Following could be gone, if included in cashout_payto_uri
-            cashoutCurrency = db.configGet("cashout_currency"),
+            cashoutCurrency = ctx.cashoutCurrency,
             passwordHash = CryptoUtil.hashpw(req.password),
         )
         val newCustomerRowId = db.customerCreate(newCustomer)
@@ -92,10 +91,7 @@ fun Routing.accountsMgmtHandlers(db: Database) {
         /* Crashing here won't break data consistency between customers
          * and bank accounts, because of the idempotency.  Client will
          * just have to retry.  */
-        val maxDebt = db.configGet("max_debt_ordinary_customers").run {
-            if (this == null) throw internalServerError("Max debt not 
configured")
-            parseTalerAmount(this)
-        }
+        val maxDebt = ctx.defaultCustomerDebtLimit
         val newBankAccount = BankAccount(
             hasDebt = false,
             internalPaytoUri = req.internal_payto_uri ?: genIbanPaytoUri(),
@@ -112,15 +108,8 @@ fun Routing.accountsMgmtHandlers(db: Database) {
          * bonus to it.  The configuration gets either a Taler amount (of the
          * bonus), or null if no bonus is meant to be awarded.
          */
-        val bonusAmount = db.configGet("registration_bonus")
+        val bonusAmount = if (ctx.registrationBonusEnabled) 
ctx.registrationBonus else null
         if (bonusAmount != null) {
-            // Double-checking that the currency is correct.
-            val internalCurrency = db.configGet("internal_currency")
-                ?: throw internalServerError("Bank own currency missing in the 
config")
-            val bonusAmountObj = parseTalerAmount2(bonusAmount, 
FracDigits.EIGHT)
-                ?: throw internalServerError("Bonus amount found invalid in 
the config.")
-            if (bonusAmountObj.currency != internalCurrency)
-                throw internalServerError("Bonus amount has the wrong 
currency: ${bonusAmountObj.currency}")
             val adminCustomer = db.customerGetFromLogin("admin")
                 ?: throw internalServerError("Admin customer not found")
             val adminBankAccount = 
db.bankAccountGetFromOwnerId(adminCustomer.expectRowId())
@@ -128,7 +117,7 @@ fun Routing.accountsMgmtHandlers(db: Database) {
             val adminPaysBonus = BankInternalTransaction(
                 creditorAccountId = newBankAccountId,
                 debtorAccountId = adminBankAccount.expectRowId(),
-                amount = bonusAmountObj,
+                amount = bonusAmount,
                 subject = "Registration bonus.",
                 transactionDate = getNowUs()
             )
diff --git a/bank/src/main/kotlin/tech/libeufin/bank/helpers.kt 
b/bank/src/main/kotlin/tech/libeufin/bank/helpers.kt
index df50d860..c9794b8b 100644
--- a/bank/src/main/kotlin/tech/libeufin/bank/helpers.kt
+++ b/bank/src/main/kotlin/tech/libeufin/bank/helpers.kt
@@ -354,7 +354,6 @@ fun isBalanceEnough(
         (normalDiff.frac > normalMaxDebt.frac)) return false
     return true
 }
-fun getBankCurrency(db: Database): String = db.configGet("internal_currency") 
?: throw internalServerError("Bank lacks currency")
 
 /**
  *  Builds the taler://withdraw-URI.  Such URI will serve the requests
@@ -465,7 +464,7 @@ fun getHistoryParams(req: ApplicationRequest): 
HistoryParams {
  *
  * It returns false in case of problems, true otherwise.
  */
-fun maybeCreateAdminAccount(db: Database): Boolean {
+fun maybeCreateAdminAccount(db: Database, ctx: BankApplicationContext): 
Boolean {
     val maybeAdminCustomer = db.customerGetFromLogin("admin")
     val adminCustomerId: Long = if (maybeAdminCustomer == null) {
         logger.debug("Creating admin's customer row")
@@ -487,26 +486,8 @@ fun maybeCreateAdminAccount(db: Database): Boolean {
         maybeAdminCustomer.expectRowId()
     val maybeAdminBankAccount = db.bankAccountGetFromOwnerId(adminCustomerId)
     if (maybeAdminBankAccount == null) {
-        logger.debug("Creating admin's bank account row.")
-        val adminMaxDebt = db.configGet("admin_max_debt")
-        if (adminMaxDebt == null) {
-            logger.error("admin_max_debt not found in the config.")
-            return false
-        }
-        val adminMaxDebtObj = parseTalerAmount2(adminMaxDebt, FracDigits.EIGHT)
-        if (adminMaxDebtObj == null) {
-            logger.error("admin_max_debt was invalid in the config.")
-            return false
-        }
-        val internalCurrency = db.configGet("internal_currency")
-        if (internalCurrency == null) {
-            logger.error("Bank own currency (internal_currency) not found in 
the config.")
-            exitProcess(1)
-        }
-        if (adminMaxDebtObj.currency != internalCurrency) {
-            logger.error("admin_max_debt has an unsupported currency: 
${adminMaxDebtObj.currency}.")
-            return false
-        }
+        logger.info("Creating admin bank account")
+        val adminMaxDebtObj = ctx.defaultAdminDebtLimit
         val adminBankAccount = BankAccount(
             hasDebt = false,
             internalPaytoUri = genIbanPaytoUri(),
@@ -516,7 +497,7 @@ fun maybeCreateAdminAccount(db: Database): Boolean {
             maxDebt = adminMaxDebtObj
         )
         if (db.bankAccountCreate(adminBankAccount) == null) {
-            logger.error("Failed at creating admin's bank account row.")
+            logger.error("Failed to creating admin bank account.")
             return false
         }
     }
diff --git 
a/bank/src/main/kotlin/tech/libeufin/bank/talerIntegrationHandlers.kt 
b/bank/src/main/kotlin/tech/libeufin/bank/talerIntegrationHandlers.kt
index 69381395..1442fbd2 100644
--- a/bank/src/main/kotlin/tech/libeufin/bank/talerIntegrationHandlers.kt
+++ b/bank/src/main/kotlin/tech/libeufin/bank/talerIntegrationHandlers.kt
@@ -28,10 +28,9 @@ import io.ktor.server.routing.*
 import net.taler.common.errorcodes.TalerErrorCode
 import tech.libeufin.util.getBaseUrl
 
-fun Routing.talerIntegrationHandlers(db: Database) {
+fun Routing.talerIntegrationHandlers(db: Database, ctx: 
BankApplicationContext) {
     get("/taler-integration/config") {
-        val internalCurrency: String = db.configGet("internal_currency")
-            ?: throw internalServerError("Currency not found")
+        val internalCurrency: String = ctx.currency
         call.respond(TalerIntegrationConfigResponse(currency = 
internalCurrency))
         return@get
     }
@@ -42,8 +41,7 @@ fun Routing.talerIntegrationHandlers(db: Database) {
         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 suggestedExchange = ctx.suggestedWithdrawalExchange
         val walletCustomer = 
db.customerGetFromRowId(relatedBankAccount.owningCustomerId)
         if (walletCustomer == null)
             throw internalServerError("Could not resort the username that owns 
this withdrawal")
@@ -84,9 +82,6 @@ fun Routing.talerIntegrationHandlers(db: Database) {
                     TalerErrorCode.TALER_EC_BANK_DUPLICATE_RESERVE_PUB_SUBJECT
                 )
             val exchangePayto = req.selected_exchange
-                ?: (db.configGet("suggested_exchange")
-                    ?: throw internalServerError("Suggested exchange not 
found")
-                        )
             db.talerWithdrawalSetDetails(
                 op.withdrawalUuid,
                 exchangePayto,
diff --git 
a/bank/src/main/kotlin/tech/libeufin/bank/talerWireGatewayHandlers.kt 
b/bank/src/main/kotlin/tech/libeufin/bank/talerWireGatewayHandlers.kt
index 85d2ca54..619e5fc8 100644
--- a/bank/src/main/kotlin/tech/libeufin/bank/talerWireGatewayHandlers.kt
+++ b/bank/src/main/kotlin/tech/libeufin/bank/talerWireGatewayHandlers.kt
@@ -29,11 +29,9 @@ import io.ktor.server.routing.*
 import net.taler.common.errorcodes.TalerErrorCode
 import tech.libeufin.util.getNowUs
 
-fun Routing.talerWireGatewayHandlers(db: Database) {
+fun Routing.talerWireGatewayHandlers(db: Database, ctx: 
BankApplicationContext) {
     get("/taler-wire-gateway/config") {
-        val internalCurrency = db.configGet("internal_currency")
-            ?: throw internalServerError("Could not find bank own currency.")
-        call.respond(TWGConfigResponse(currency = internalCurrency))
+        call.respond(TWGConfigResponse(currency = ctx.currency))
         return@get
     }
     get("/accounts/{USERNAME}/taler-wire-gateway/history/incoming") {
@@ -93,8 +91,7 @@ fun Routing.talerWireGatewayHandlers(db: Database) {
             )
         }
         // Legitimate request, go on.
-        val internalCurrency = db.configGet("internal_currency")
-            ?: throw internalServerError("Bank did not find own internal 
currency.")
+        val internalCurrency = ctx.currency
         if (internalCurrency != req.amount.currency)
             throw badRequest("Currency mismatch: $internalCurrency vs 
${req.amount.currency}")
         val exchangeBankAccount = db.bankAccountGetFromOwnerId(c.expectRowId())
@@ -128,8 +125,7 @@ fun Routing.talerWireGatewayHandlers(db: Database) {
         if (!call.getResourceName("USERNAME").canI(c, withAdmin = false)) 
throw forbidden()
         val req = call.receive<AddIncomingRequest>()
         val amount = parseTalerAmount(req.amount)
-        val internalCurrency = db.configGet("internal_currency")
-            ?: throw internalServerError("Bank didn't find own currency.")
+        val internalCurrency = ctx.currency
         if (amount.currency != internalCurrency)
             throw badRequest(
                 "Currency mismatch",
diff --git a/bank/src/main/kotlin/tech/libeufin/bank/tokenHandlers.kt 
b/bank/src/main/kotlin/tech/libeufin/bank/tokenHandlers.kt
index 98166116..7160f991 100644
--- a/bank/src/main/kotlin/tech/libeufin/bank/tokenHandlers.kt
+++ b/bank/src/main/kotlin/tech/libeufin/bank/tokenHandlers.kt
@@ -32,7 +32,7 @@ import tech.libeufin.util.getNowUs
 
 private val logger: Logger = 
LoggerFactory.getLogger("tech.libeufin.bank.accountsMgmtHandlers")
 
-fun Routing.tokenHandlers(db: Database) {
+fun Routing.tokenHandlers(db: Database, ctx: BankApplicationContext) {
     delete("/accounts/{USERNAME}/token") {
         throw internalServerError("Token deletion not implemented.")
     }
@@ -64,17 +64,8 @@ fun Routing.tokenHandlers(db: Database) {
         val tokenBytes = ByteArray(32).apply {
             java.util.Random().nextBytes(this)
         }
-        val maxDurationTime: Long = db.configGet("token_max_duration").run {
-            if (this == null)
-                return@run Long.MAX_VALUE
-            return@run try {
-                this.toLong()
-            } catch (e: Exception) {
-                logger.error("Could not convert config's token_max_duration to 
Long")
-                throw internalServerError(e.message)
-            }
-        }
-        if (req.duration != null && 
req.duration.d_us.compareTo(maxDurationTime) == 1)
+        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.
@@ -82,7 +73,7 @@ fun Routing.tokenHandlers(db: Database) {
             )
         val tokenDurationUs  = req.duration?.d_us ?: TOKEN_DEFAULT_DURATION_US
         val customerDbRow = customer.dbRowId ?: throw internalServerError(
-            "Coud not resort customer '${customer.login}' database row ID"
+            "Could not resort customer '${customer.login}' database row ID"
         )
         val expirationTimestampUs: Long = getNowUs() + tokenDurationUs
         if (expirationTimestampUs < tokenDurationUs)
diff --git a/bank/src/main/kotlin/tech/libeufin/bank/transactionsHandlers.kt 
b/bank/src/main/kotlin/tech/libeufin/bank/transactionsHandlers.kt
index c6f67a61..64266110 100644
--- a/bank/src/main/kotlin/tech/libeufin/bank/transactionsHandlers.kt
+++ b/bank/src/main/kotlin/tech/libeufin/bank/transactionsHandlers.kt
@@ -16,7 +16,7 @@ import kotlin.math.abs
 
 private val logger: Logger = 
LoggerFactory.getLogger("tech.libeufin.bank.transactionHandlers")
 
-fun Routing.transactionsHandlers(db: Database) {
+fun Routing.transactionsHandlers(db: Database, ctx: BankApplicationContext) {
     get("/accounts/{USERNAME}/transactions") {
         val c = call.myAuth(db, TokenScope.readonly) ?: throw unauthorized()
         val resourceName = call.expectUriComponent("USERNAME")
@@ -70,7 +70,7 @@ fun Routing.transactionsHandlers(db: Database) {
                 TalerErrorCode.TALER_EC_END // FIXME: define this EC.
             )
         val amount = parseTalerAmount(txData.amount)
-        if (amount.currency != getBankCurrency(db))
+        if (amount.currency != ctx.currency)
             throw badRequest(
                 "Wrong currency: ${amount.currency}",
                 talerErrorCode = 
TalerErrorCode.TALER_EC_GENERIC_CURRENCY_MISMATCH
diff --git a/bank/src/main/kotlin/tech/libeufin/bank/types.kt 
b/bank/src/main/kotlin/tech/libeufin/bank/types.kt
index e9d8372f..86c5dbf7 100644
--- a/bank/src/main/kotlin/tech/libeufin/bank/types.kt
+++ b/bank/src/main/kotlin/tech/libeufin/bank/types.kt
@@ -146,17 +146,17 @@ data class Customer(
 )
 
 /**
-* Represents a Taler amount.  This type can be used both
-* to hold database records and amounts coming from the parser.
-* If maybeCurrency is null, then the constructor defaults it
-* to be the "internal currency".  Internal currency is the one
-* with which Libeufin-Bank moves funds within itself, therefore
-* not to be mistaken with the cashout currency, which is the one
-* that gets credited to Libeufin-Bank users to their cashout_payto_uri.
-*
-* maybeCurrency is typically null when the TalerAmount object gets
-* defined by the Database class.
-*/
+ * Represents a Taler amount.  This type can be used both
+ * to hold database records and amounts coming from the parser.
+ * If maybeCurrency is null, then the constructor defaults it
+ * to be the "internal currency".  Internal currency is the one
+ * with which Libeufin-Bank moves funds within itself, therefore
+ * not to be mistaken with the cashout currency, which is the one
+ * that gets credited to Libeufin-Bank users to their cashout_payto_uri.
+ *
+ * maybeCurrency is typically null when the TalerAmount object gets
+ * defined by the Database class.
+ */
 class TalerAmount(
     val value: Long,
     val frac: Int,
@@ -437,6 +437,7 @@ enum class WithdrawalConfirmationResult {
     OP_NOT_FOUND,
     EXCHANGE_NOT_FOUND,
     BALANCE_INSUFFICIENT,
+
     /**
      * This state indicates that the withdrawal was already
      * confirmed BUT Kotlin did not detect it and still invoked
@@ -496,7 +497,7 @@ data class BankWithdrawalOperationStatus(
 @Serializable
 data class BankWithdrawalOperationPostRequest(
     val reserve_pub: String,
-    val selected_exchange: String? = null // Use suggested exchange if that's 
missing.
+    val selected_exchange: String,
 )
 
 /**
@@ -540,6 +541,7 @@ data class IncomingHistory(
     val incoming_transactions: MutableList<IncomingReserveTransaction> = 
mutableListOf(),
     val credit_account: String // Receiver's Payto URI.
 )
+
 // TWG's incoming payment record.
 @Serializable
 data class IncomingReserveTransaction(
diff --git a/bank/src/test/kotlin/AmountTest.kt 
b/bank/src/test/kotlin/AmountTest.kt
index de51613b..4677493e 100644
--- a/bank/src/test/kotlin/AmountTest.kt
+++ b/bank/src/test/kotlin/AmountTest.kt
@@ -70,16 +70,6 @@ class AmountTest {
 
     }
 
-    /* Testing that currency is fetched from the config
-       and set in the TalerAmount dedicated field. */
-    @Test
-    fun testAutoCurrency() {
-        val db = initDb()
-        db.configSet("internal_currency", "KUDOS")
-        val a = TalerAmount(1L, 0, getBankCurrency(db))
-        assert(a.currency == "KUDOS")
-    }
-
     @Test
     fun parseTalerAmountTest() {
         val one = "EUR:1"
diff --git a/bank/src/test/kotlin/Common.kt b/bank/src/test/kotlin/Common.kt
index 52547e88..47adc78f 100644
--- a/bank/src/test/kotlin/Common.kt
+++ b/bank/src/test/kotlin/Common.kt
@@ -17,7 +17,9 @@
  * <http://www.gnu.org/licenses/>
  */
 
+import tech.libeufin.bank.BankApplicationContext
 import tech.libeufin.bank.Database
+import tech.libeufin.bank.TalerAmount
 import tech.libeufin.util.execCommand
 
 // Init the database and sets the currency to KUDOS.
@@ -35,7 +37,22 @@ fun initDb(): Database {
         ),
         throwIfFails = true
     )
-    val db = Database("jdbc:postgresql:///libeufincheck")
-    db.configSet("internal_currency", "KUDOS")
-    return db
+    return Database("jdbc:postgresql:///libeufincheck", "KUDOS")
+}
+
+fun getTestContext(
+    restrictRegistration: Boolean = false,
+    suggestedExchange: String = "https://exchange.example.com";
+): BankApplicationContext {
+    return BankApplicationContext(
+        currency = "KUDOS",
+        restrictRegistration = restrictRegistration,
+        cashoutCurrency = "EUR",
+        defaultCustomerDebtLimit = TalerAmount(100, 0, "KUDOS"),
+        defaultAdminDebtLimit = TalerAmount(10000, 0, "KUDOS"),
+        registrationBonusEnabled = false,
+        registrationBonus = null,
+        suggestedWithdrawalExchange = suggestedExchange,
+        maxAuthTokenDurationUs = 200 * 1000000,
+    )
 }
\ No newline at end of file
diff --git a/bank/src/test/kotlin/DatabaseTest.kt 
b/bank/src/test/kotlin/DatabaseTest.kt
index 83741688..75614118 100644
--- a/bank/src/test/kotlin/DatabaseTest.kt
+++ b/bank/src/test/kotlin/DatabaseTest.kt
@@ -79,14 +79,14 @@ class DatabaseTest {
     @Test
     fun createAdminTest() {
         val db = initDb()
+        val ctx = getTestContext()
         val noAdminCustomer = db.customerGetFromLogin("admin")
         assert(noAdminCustomer == null)
-        db.configSet("admin_max_debt", "KUDOS:2222")
-        assert(maybeCreateAdminAccount(db))
+        assert(maybeCreateAdminAccount(db, ctx))
         val yesAdminCustomer = db.customerGetFromLogin("admin")
         assert(yesAdminCustomer != null)
         assert(db.bankAccountGetFromOwnerId(yesAdminCustomer!!.expectRowId()) 
!= null)
-        assert(maybeCreateAdminAccount(db))
+        assert(maybeCreateAdminAccount(db, ctx))
     }
 
     /**
@@ -224,14 +224,7 @@ class DatabaseTest {
         // Trigger conflict.
         assert(db.customerCreate(customerFoo) == null)
     }
-    @Test
-    fun configTest() {
-        val db = initDb()
-        assert(db.configGet("bar") == null)
-        assert(db.configGet("bar") == null)
-        db.configSet("foo", "bar")
-        assert(db.configGet("foo") == "bar")
-    }
+
     @Test
     fun bankAccountTest() {
         val db = initDb()
diff --git a/bank/src/test/kotlin/LibeuFinApiTest.kt 
b/bank/src/test/kotlin/LibeuFinApiTest.kt
index 273b3055..06a3f47a 100644
--- a/bank/src/test/kotlin/LibeuFinApiTest.kt
+++ b/bank/src/test/kotlin/LibeuFinApiTest.kt
@@ -42,14 +42,16 @@ class LibeuFinApiTest {
     @Test
     fun getConfig() {
         val db = initDb()
+        val ctx = getTestContext()
         testApplication {
-            application { corebankWebApp(db) }
+            application { corebankWebApp(db, ctx) }
             val r = client.get("/config") {
                 expectSuccess = true
             }
             println(r.bodyAsText())
         }
     }
+
     /**
      * Testing GET /transactions.  This test checks that the sign
      * of delta gets honored by the HTTP handler, namely that the
@@ -59,14 +61,17 @@ class LibeuFinApiTest {
     @Test
     fun testHistory() {
         val db = initDb()
+        val ctx = getTestContext()
         val fooId = db.customerCreate(customerFoo); assert(fooId != null)
         assert(db.bankAccountCreate(genBankAccount(fooId!!)) != null)
         val barId = db.customerCreate(customerBar); assert(barId != null)
         assert(db.bankAccountCreate(genBankAccount(barId!!)) != null)
-        for (i in 1..10) { db.bankTransactionCreate(genTx("test-$i")) }
+        for (i in 1..10) {
+            db.bankTransactionCreate(genTx("test-$i"))
+        }
         testApplication {
             application {
-                corebankWebApp(db)
+                corebankWebApp(db, ctx)
             }
             val asc = client.get("/accounts/foo/transactions?delta=2") {
                 basicAuth("foo", "pw")
@@ -89,6 +94,7 @@ class LibeuFinApiTest {
     @Test
     fun postTransactionsTest() {
         val db = initDb()
+        val ctx = getTestContext()
         // foo account
         val fooId = db.customerCreate(customerFoo); assert(fooId != null)
         assert(db.bankAccountCreate(genBankAccount(fooId!!)) != null)
@@ -98,18 +104,20 @@ class LibeuFinApiTest {
         // accounts exist, now create one transaction.
         testApplication {
             application {
-                corebankWebApp(db)
+                corebankWebApp(db, ctx)
             }
             client.post("/accounts/foo/transactions") {
                 expectSuccess = true
                 basicAuth("foo", "pw")
                 contentType(ContentType.Application.Json)
                 // expectSuccess = true
-                setBody("""{
+                setBody(
+                    """{
                     "payto_uri": 
"payto://iban/SANDBOXX/${barId}-IBAN?message=payout", 
                     "amount": "KUDOS:3.3"
                 }
-                """.trimIndent())
+                """.trimIndent()
+                )
             }
             // Getting the only tx that exists in the DB, hence has ID == 1.
             val r = client.get("/accounts/foo/transactions/1") {
@@ -120,22 +128,26 @@ class LibeuFinApiTest {
             assert(obj.subject == "payout")
         }
     }
+
     // Checking the POST /token handling.
     @Test
     fun tokenTest() {
         val db = initDb()
+        val ctx = getTestContext()
         assert(db.customerCreate(customerFoo) != null)
         testApplication {
             application {
-                corebankWebApp(db)
+                corebankWebApp(db, ctx)
             }
             client.post("/accounts/foo/token") {
                 expectSuccess = true
                 contentType(ContentType.Application.Json)
                 basicAuth("foo", "pw")
-                setBody("""
+                setBody(
+                    """
                     {"scope": "readonly"}
-                """.trimIndent())
+                """.trimIndent()
+                )
             }
             // foo tries on bar endpoint
             val r = client.post("/accounts/bar/token") {
@@ -145,14 +157,18 @@ class LibeuFinApiTest {
             assert(r.status == HttpStatusCode.Forbidden)
             // Make ad-hoc token for foo.
             val fooTok = ByteArray(32).apply { Random.nextBytes(this) }
-            assert(db.bearerTokenCreate(BearerToken(
-                content = fooTok,
-                bankCustomer = 1L, // only foo exists.
-                scope = TokenScope.readonly,
-                creationTime = getNowUs(),
-                isRefreshable = true,
-                expirationTime = getNowUs() + (Duration.ofHours(1).toMillis() 
* 1000)
-            )))
+            assert(
+                db.bearerTokenCreate(
+                    BearerToken(
+                        content = fooTok,
+                        bankCustomer = 1L, // only foo exists.
+                        scope = TokenScope.readonly,
+                        creationTime = getNowUs(),
+                        isRefreshable = true,
+                        expirationTime = getNowUs() + 
(Duration.ofHours(1).toMillis() * 1000)
+                    )
+                )
+            )
             // Testing the bearer-token:-scheme.
             client.post("/accounts/foo/token") {
                 headers.set("Authorization", "Bearer 
bearer-token:${Base32Crockford.encode(fooTok)}")
@@ -172,23 +188,28 @@ class LibeuFinApiTest {
     fun getAccountTest() {
         // Artificially insert a customer and bank account in the database.
         val db = initDb()
-        val customerRowId = db.customerCreate(Customer(
-            "foo",
-            CryptoUtil.hashpw("pw"),
-            "Foo"
-        ))
-        assert(customerRowId != null)
-        assert(db.bankAccountCreate(
-            BankAccount(
-                hasDebt = false,
-                internalPaytoUri = "payto://iban/SANDBOXX/FOO-IBAN",
-                maxDebt = TalerAmount(100, 0, "KUDOS"),
-                owningCustomerId = customerRowId!!
+        val ctx = getTestContext()
+        val customerRowId = db.customerCreate(
+            Customer(
+                "foo",
+                CryptoUtil.hashpw("pw"),
+                "Foo"
             )
-        ) != null)
+        )
+        assert(customerRowId != null)
+        assert(
+            db.bankAccountCreate(
+                BankAccount(
+                    hasDebt = false,
+                    internalPaytoUri = "payto://iban/SANDBOXX/FOO-IBAN",
+                    maxDebt = TalerAmount(100, 0, "KUDOS"),
+                    owningCustomerId = customerRowId!!
+                )
+            ) != null
+        )
         testApplication {
             application {
-                corebankWebApp(db)
+                corebankWebApp(db, ctx)
             }
             val r = client.get("/accounts/foo") {
                 expectSuccess = true
@@ -197,18 +218,24 @@ class LibeuFinApiTest {
             val obj: AccountData = Json.decodeFromString(r.bodyAsText())
             assert(obj.name == "Foo")
             // Checking admin can.
-            val adminRowId = db.customerCreate(Customer(
-                "admin",
-                CryptoUtil.hashpw("admin"),
-                "Admin"
-            ))
+            val adminRowId = db.customerCreate(
+                Customer(
+                    "admin",
+                    CryptoUtil.hashpw("admin"),
+                    "Admin"
+                )
+            )
             assert(adminRowId != null)
-            assert(db.bankAccountCreate(BankAccount(
-                hasDebt = false,
-                internalPaytoUri = "payto://iban/SANDBOXX/ADMIN-IBAN",
-                maxDebt = TalerAmount(100, 0, "KUDOS"),
-                owningCustomerId = adminRowId!!
-            )) != null)
+            assert(
+                db.bankAccountCreate(
+                    BankAccount(
+                        hasDebt = false,
+                        internalPaytoUri = "payto://iban/SANDBOXX/ADMIN-IBAN",
+                        maxDebt = TalerAmount(100, 0, "KUDOS"),
+                        owningCustomerId = adminRowId!!
+                    )
+                ) != null
+            )
             client.get("/accounts/foo") {
                 expectSuccess = true
                 basicAuth("admin", "admin")
@@ -220,75 +247,97 @@ class LibeuFinApiTest {
             assert(shouldNot.status == HttpStatusCode.NotFound)
         }
     }
+
     /**
-     * Testing the account creation, its idempotency and
-     * the restriction to admin to create accounts.
+     * Testing the account creation and its idempotency
      */
     @Test
     fun createAccountTest() {
         testApplication {
             val db = initDb()
+            val ctx = getTestContext()
             val ibanPayto = genIbanPaytoUri()
-            // Bank needs those to operate:
-            db.configSet("max_debt_ordinary_customers", "KUDOS:11")
             application {
-                corebankWebApp(db)
+                corebankWebApp(db, ctx)
             }
             var resp = client.post("/accounts") {
                 expectSuccess = false
                 contentType(ContentType.Application.Json)
-                setBody("""{
+                setBody(
+                    """{
                     "username": "foo",
                     "password": "bar",
                     "name": "Jane",
                     "internal_payto_uri": "$ibanPayto"
-                }""".trimIndent())
+                }""".trimIndent()
+                )
             }
             assert(resp.status == HttpStatusCode.Created)
             // Testing idempotency.
             resp = client.post("/accounts") {
                 expectSuccess = false
                 contentType(ContentType.Application.Json)
-                setBody("""{
+                setBody(
+                    """{
                     "username": "foo",
                     "password": "bar",
                     "name": "Jane",
                     "internal_payto_uri": "$ibanPayto"
-                }""".trimIndent())
+                }""".trimIndent()
+                )
             }
             assert(resp.status == HttpStatusCode.Created)
             // Creating the administrator.
-            db.customerCreate(Customer(
-                "admin",
-                CryptoUtil.hashpw("pass"),
-                "CFO"
-            ))
-            db.configSet("only_admin_registrations", "yes")
+            db.customerCreate(
+                Customer(
+                    "admin",
+                    CryptoUtil.hashpw("pass"),
+                    "CFO"
+                )
+            )
+        }
+    }
+
+    /**
+     * Test admin-only account creation
+     */
+    @Test
+    fun createAccountRestrictedTest() {
+        testApplication {
+            val db = initDb()
+            // For this test, we restrict registrations
+            val ctx = getTestContext(restrictRegistration = true)
+
+            application {
+                corebankWebApp(db, ctx)
+            }
+
             // Ordinary user tries, should fail.
-            resp = client.post("/accounts") {
+            var resp = client.post("/accounts") {
                 expectSuccess = false
                 basicAuth("foo", "bar")
                 contentType(ContentType.Application.Json)
-                setBody("""{
+                setBody(
+                    """{
                     "username": "baz",
                     "password": "xyz",
                     "name": "Mallory"
-                }""".trimIndent())
+                }""".trimIndent()
+                )
             }
             assert(resp.status == HttpStatusCode.Unauthorized)
-            // admin tries (also giving bonus), should succeed
-            db.configSet("admin_max_debt", "KUDOS:2222")
-            db.configSet("registration_bonus", "KUDOS:32")
-            assert(maybeCreateAdminAccount(db)) // customer exists, this makes 
only the bank account.
+            assert(maybeCreateAdminAccount(db, ctx)) // customer exists, this 
makes only the bank account.
             resp = client.post("/accounts") {
                 expectSuccess = false
                 basicAuth("admin", "pass")
                 contentType(ContentType.Application.Json)
-                setBody("""{
+                setBody(
+                    """{
                     "username": "baz",
                     "password": "xyz",
                     "name": "Mallory"
-                }""".trimIndent())
+                }""".trimIndent()
+                )
             }
             assert(resp.status == HttpStatusCode.Created)
         }
diff --git a/bank/src/test/kotlin/TalerApiTest.kt 
b/bank/src/test/kotlin/TalerApiTest.kt
index 7cdcd0eb..64a33bac 100644
--- a/bank/src/test/kotlin/TalerApiTest.kt
+++ b/bank/src/test/kotlin/TalerApiTest.kt
@@ -47,6 +47,7 @@ class TalerApiTest {
     @Test
     fun transfer() {
         val db = initDb()
+        val ctx = getTestContext()
         // Creating the exchange and merchant accounts first.
         assert(db.customerCreate(customerFoo) != null)
         assert(db.bankAccountCreate(bankAccountFoo) != null)
@@ -60,7 +61,7 @@ class TalerApiTest {
         // Do POST /transfer.
         testApplication {
             application {
-                corebankWebApp(db)
+                corebankWebApp(db, ctx)
             }
             val req = """
                     {
@@ -125,6 +126,7 @@ class TalerApiTest {
     @Test
     fun historyIncoming() {
         val db = initDb()
+        val ctx = getTestContext()
         assert(db.customerCreate(customerFoo) != null)
         assert(db.bankAccountCreate(bankAccountFoo) != null)
         assert(db.customerCreate(customerBar) != null)
@@ -145,7 +147,7 @@ class TalerApiTest {
         // Bar expects two entries in the incoming history
         testApplication {
             application {
-                corebankWebApp(db)
+                corebankWebApp(db, ctx)
             }
             val resp = 
client.get("/accounts/bar/taler-wire-gateway/history/incoming?delta=5") {
                 basicAuth("bar", "secret")
@@ -160,6 +162,7 @@ class TalerApiTest {
     @Test
     fun addIncoming() {
         val db = initDb()
+        val ctx = getTestContext()
         assert(db.customerCreate(customerFoo) != null)
         assert(db.bankAccountCreate(bankAccountFoo) != null)
         assert(db.customerCreate(customerBar) != null)
@@ -171,7 +174,7 @@ class TalerApiTest {
         ))
         testApplication {
             application {
-                corebankWebApp(db)
+                corebankWebApp(db, ctx)
             }
             client.post("/accounts/foo/taler-wire-gateway/admin/add-incoming") 
{
                 expectSuccess = true
@@ -190,13 +193,10 @@ class TalerApiTest {
     @Test
     fun intSelect() {
         val db = initDb()
+        val ctx = getTestContext(suggestedExchange = 
"payto://suggested-exchange")
         val uuid = UUID.randomUUID()
         assert(db.customerCreate(customerFoo) != null)
         assert(db.bankAccountCreate(bankAccountFoo) != null)
-        db.configSet(
-            "suggested_exchange",
-            "payto://suggested-exchange"
-        )
         // insert new.
         assert(db.talerWithdrawalCreate(
             opUUID = uuid,
@@ -205,7 +205,7 @@ class TalerApiTest {
         ))
         testApplication {
             application {
-                corebankWebApp(db)
+                corebankWebApp(db, ctx)
             }
             val r = 
client.post("/taler-integration/withdrawal-operation/${uuid}") {
                 expectSuccess = true
@@ -225,10 +225,7 @@ class TalerApiTest {
         val uuid = UUID.randomUUID()
         assert(db.customerCreate(customerFoo) != null)
         assert(db.bankAccountCreate(bankAccountFoo) != null)
-        db.configSet(
-            "suggested_exchange",
-            "payto://suggested-exchange"
-        )
+        val ctx = getTestContext(suggestedExchange = 
"payto://suggested-exchange")
         // insert new.
         assert(db.talerWithdrawalCreate(
             opUUID = uuid,
@@ -237,7 +234,7 @@ class TalerApiTest {
         ))
         testApplication {
             application {
-                corebankWebApp(db)
+                corebankWebApp(db, ctx)
             }
             val r = 
client.get("/taler-integration/withdrawal-operation/${uuid}") {
                 expectSuccess = true
@@ -250,6 +247,7 @@ class TalerApiTest {
     fun withdrawalAbort() {
         val db = initDb()
         val uuid = UUID.randomUUID()
+        val ctx = getTestContext()
         assert(db.customerCreate(customerFoo) != null)
         assert(db.bankAccountCreate(bankAccountFoo) != null)
         // insert new.
@@ -262,7 +260,7 @@ class TalerApiTest {
         assert(op?.aborted == false)
         testApplication {
             application {
-                corebankWebApp(db)
+                corebankWebApp(db, ctx)
             }
             client.post("/accounts/foo/withdrawals/${uuid}/abort") {
                 expectSuccess = true
@@ -276,11 +274,12 @@ class TalerApiTest {
     @Test
     fun withdrawalCreation() {
         val db = initDb()
+        val ctx = getTestContext()
         assert(db.customerCreate(customerFoo) != null)
         assert(db.bankAccountCreate(bankAccountFoo) != null)
         testApplication {
             application {
-                corebankWebApp(db)
+                corebankWebApp(db, ctx)
             }
             // Creating the withdrawal as if the SPA did it.
             val r = client.post("/accounts/foo/withdrawals") {
@@ -303,6 +302,7 @@ class TalerApiTest {
     @Test
     fun withdrawalConfirmation() {
         val db = initDb()
+        val ctx = getTestContext()
         // Creating Foo as the wallet owner and Bar as the exchange.
         assert(db.customerCreate(customerFoo) != null)
         assert(db.bankAccountCreate(bankAccountFoo) != null)
@@ -326,7 +326,7 @@ class TalerApiTest {
         // Starting the bank and POSTing as Foo to /confirm the operation.
         testApplication {
             application {
-                corebankWebApp(db)
+                corebankWebApp(db, ctx)
             }
             client.post("/accounts/foo/withdrawals/${uuid}/confirm") {
                 expectSuccess = true // Sufficient to assert on success.
diff --git a/contrib/wallet-core b/contrib/wallet-core
index c5a3cd4c..9e2d95b3 160000
--- a/contrib/wallet-core
+++ b/contrib/wallet-core
@@ -1 +1 @@
-Subproject commit c5a3cd4c50676c49fa6c67cbdeb609101c38e764
+Subproject commit 9e2d95b39723a038eb714d723ac0910a5bf596e2
diff --git a/database-versioning/libeufin-bank-0001.sql 
b/database-versioning/libeufin-bank-0001.sql
index e09b8367..acd4f174 100644
--- a/database-versioning/libeufin-bank-0001.sql
+++ b/database-versioning/libeufin-bank-0001.sql
@@ -49,15 +49,6 @@ CREATE TYPE subscriber_state_enum
 
 -- FIXME: comments on types (see exchange for example)!
 
--- start of: bank config tables.  FIXME: eventually replaced by the INI file.
-
-CREATE TABLE IF NOT EXISTS configuration
-  (config_key TEXT PRIMARY KEY
-  ,config_value TEXT
-  );
-
--- end of: bank config tables
-
 -- start of: bank accounts
 
 CREATE TABLE IF NOT EXISTS customers
diff --git a/util/src/main/kotlin/TalerConfig.kt 
b/util/src/main/kotlin/TalerConfig.kt
index e74e9584..6ea252b2 100644
--- a/util/src/main/kotlin/TalerConfig.kt
+++ b/util/src/main/kotlin/TalerConfig.kt
@@ -114,10 +114,10 @@ class TalerConfig {
     /**
      * Look up a string value from the configuration.
      *
-     * Return an empty Optional if the value was not found in the 
configuration.
+     * Return null if the value was not found in the configuration.
      */
-    fun lookupValueString(section: String, option: String): Optional<String> {
-        return Optional.ofNullable(lookupEntry(section, option)?.value)
+    fun lookupValueString(section: String, option: String): String? {
+        return lookupEntry(section, option)?.value
     }
 
     fun requireValueString(section: String, option: String): String {
@@ -128,6 +128,21 @@ class TalerConfig {
         return entry.value
     }
 
+    fun lookupValueBooleanDefault(section: String, option: String, default: 
Boolean): Boolean {
+        val entry = lookupEntry(section, option)
+        if (entry == null) {
+            return default
+        }
+        val v = entry.value.lowercase()
+        if (v == "yes") {
+            return true;
+        }
+        if (v == "false") {
+            return false;
+        }
+        throw TalerConfigError("expected yes/no in configuration section 
$section option $option but got $v")
+    }
+
     /**
      * Create a string representation of the loaded configuration.
      */
diff --git a/util/src/test/kotlin/TalerConfigTest.kt 
b/util/src/test/kotlin/TalerConfigTest.kt
index 216528c0..39977599 100644
--- a/util/src/test/kotlin/TalerConfigTest.kt
+++ b/util/src/test/kotlin/TalerConfigTest.kt
@@ -38,7 +38,7 @@ class TalerConfigTest {
 
         println(conf.stringify())
 
-        assertEquals("baz", conf.lookupValueString("foo", "bar").orElseThrow())
+        assertEquals("baz", conf.lookupValueString("foo", "bar"))
 
         println(TalerConfig.getTalerInstallPath())
     }

-- 
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]