[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.
[Prev in Thread] |
Current Thread |
[Next in Thread] |
- [libeufin] branch master updated: read configuration from file, remove config from DB,
gnunet <=