aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAntoine A <>2023-12-02 13:03:10 +0000
committerAntoine A <>2023-12-02 13:03:10 +0000
commit653fb27660f78b19fbef32137c5c91fc9ad61dcf (patch)
tree2cdcd4b2aa0b874e7988c2b3d8774182db0516d3
parent8e43b5d1810956eaad533f9849dcf05fe176ab43 (diff)
downloadlibeufin-653fb27660f78b19fbef32137c5c91fc9ad61dcf.tar.gz
libeufin-653fb27660f78b19fbef32137c5c91fc9ad61dcf.tar.bz2
libeufin-653fb27660f78b19fbef32137c5c91fc9ad61dcf.zip
Single DEFAULT_DEBT_LIMIT config
-rw-r--r--bank/conf/test.conf3
-rw-r--r--bank/conf/test_bonus.conf1
-rw-r--r--bank/conf/test_no_conversion.conf1
-rw-r--r--bank/conf/test_no_tan.conf3
-rw-r--r--bank/conf/test_restrict.conf3
-rw-r--r--bank/src/main/kotlin/tech/libeufin/bank/Config.kt6
-rw-r--r--bank/src/main/kotlin/tech/libeufin/bank/CoreBankApi.kt66
-rw-r--r--bank/src/main/kotlin/tech/libeufin/bank/Main.kt22
-rw-r--r--bank/src/main/kotlin/tech/libeufin/bank/helpers.kt2
-rw-r--r--bank/src/test/kotlin/CoreBankApiTest.kt4
-rw-r--r--bank/src/test/kotlin/RevenueApiTest.kt2
-rw-r--r--bank/src/test/kotlin/StatsTest.kt6
-rw-r--r--bank/src/test/kotlin/WireGatewayApiTest.kt8
-rw-r--r--bank/src/test/kotlin/helpers.kt2
-rw-r--r--contrib/bank.conf31
-rw-r--r--debian/etc/libeufin/libeufin-bank.conf15
-rw-r--r--integration/conf/integration.conf2
-rw-r--r--integration/test/IntegrationTest.kt10
18 files changed, 87 insertions, 100 deletions
diff --git a/bank/conf/test.conf b/bank/conf/test.conf
index afa4530b..96d80b0f 100644
--- a/bank/conf/test.conf
+++ b/bank/conf/test.conf
@@ -1,7 +1,6 @@
[libeufin-bank]
CURRENCY = KUDOS
-DEFAULT_CUSTOMER_DEBT_LIMIT = KUDOS:100
-DEFAULT_ADMIN_DEBT_LIMIT = KUDOS:10000
+DEFAULT_DEBT_LIMIT = KUDOS:100
SUGGESTED_WITHDRAWAL_EXCHANGE = https://exchange.example.com
ALLOW_REGISTRATION = yes
ALLOW_ACCOUNT_DELETION = yes
diff --git a/bank/conf/test_bonus.conf b/bank/conf/test_bonus.conf
index 09bb5146..b6126109 100644
--- a/bank/conf/test_bonus.conf
+++ b/bank/conf/test_bonus.conf
@@ -1,6 +1,5 @@
[libeufin-bank]
CURRENCY = KUDOS
-DEFAULT_ADMIN_DEBT_LIMIT = KUDOS:10000
REGISTRATION_BONUS = KUDOS:100
ALLOW_REGISTRATION = yes
ALLOW_ACCOUNT_DELETION = yes
diff --git a/bank/conf/test_no_conversion.conf b/bank/conf/test_no_conversion.conf
index ac67d6e4..b1912331 100644
--- a/bank/conf/test_no_conversion.conf
+++ b/bank/conf/test_no_conversion.conf
@@ -1,6 +1,5 @@
[libeufin-bank]
CURRENCY = KUDOS
-DEFAULT_ADMIN_DEBT_LIMIT = KUDOS:10000
ALLOW_REGISTRATION = yes
ALLOW_ACCOUNT_DELETION = yes
diff --git a/bank/conf/test_no_tan.conf b/bank/conf/test_no_tan.conf
index 5bf08d43..c031f3fc 100644
--- a/bank/conf/test_no_tan.conf
+++ b/bank/conf/test_no_tan.conf
@@ -1,7 +1,6 @@
[libeufin-bank]
CURRENCY = KUDOS
-DEFAULT_CUSTOMER_DEBT_LIMIT = KUDOS:100
-DEFAULT_ADMIN_DEBT_LIMIT = KUDOS:10000
+DEFAULT_DEBT_LIMIT = KUDOS:100
SUGGESTED_WITHDRAWAL_EXCHANGE = https://exchange.example.com
allow_conversion = YES
FIAT_CURRENCY = EUR
diff --git a/bank/conf/test_restrict.conf b/bank/conf/test_restrict.conf
index 1aae6252..e1aa4f76 100644
--- a/bank/conf/test_restrict.conf
+++ b/bank/conf/test_restrict.conf
@@ -1,7 +1,6 @@
[libeufin-bank]
CURRENCY = KUDOS
-DEFAULT_CUSTOMER_DEBT_LIMIT = KUDOS:100
-DEFAULT_ADMIN_DEBT_LIMIT = KUDOS:10000
+DEFAULT_DEBT_LIMIT = KUDOS:100
allow_conversion = YES
FIAT_CURRENCY = EUR
diff --git a/bank/src/main/kotlin/tech/libeufin/bank/Config.kt b/bank/src/main/kotlin/tech/libeufin/bank/Config.kt
index a9ea31cc..6a7cd046 100644
--- a/bank/src/main/kotlin/tech/libeufin/bank/Config.kt
+++ b/bank/src/main/kotlin/tech/libeufin/bank/Config.kt
@@ -37,8 +37,7 @@ data class BankConfig(
val regionalCurrencySpec: CurrencySpecification,
val allowRegistration: Boolean,
val allowAccountDeletion: Boolean,
- val defaultCustomerDebtLimit: TalerAmount,
- val defaultAdminDebtLimit: TalerAmount,
+ val defaultDebtLimit: TalerAmount,
val registrationBonus: TalerAmount,
val suggestedWithdrawalExchange: String?,
/**
@@ -110,8 +109,7 @@ fun TalerConfig.loadBankConfig(): BankConfig {
regionalCurrencySpec = currencySpecificationFor(regionalCurrency),
allowRegistration = lookupBoolean("libeufin-bank", "allow_registration") ?: false,
allowAccountDeletion = lookupBoolean("libeufin-bank", "allow_account_deletion") ?: false,
- defaultCustomerDebtLimit = amount("libeufin-bank", "default_customer_debt_limit", regionalCurrency) ?: TalerAmount(0, 0, regionalCurrency),
- defaultAdminDebtLimit = amount("libeufin-bank", "default_admin_debt_limit", regionalCurrency) ?: TalerAmount(0, 0, regionalCurrency),
+ defaultDebtLimit = amount("libeufin-bank", "default_debt_limit", regionalCurrency) ?: TalerAmount(0, 0, regionalCurrency),
registrationBonus = amount("libeufin-bank", "registration_bonus", regionalCurrency) ?: TalerAmount(0, 0, regionalCurrency),
suggestedWithdrawalExchange = lookupString("libeufin-bank", "suggested_withdrawal_exchange"),
spaCaptchaURL = lookupString("libeufin-bank", "spa_captcha_url"),
diff --git a/bank/src/main/kotlin/tech/libeufin/bank/CoreBankApi.kt b/bank/src/main/kotlin/tech/libeufin/bank/CoreBankApi.kt
index 7e165446..060b1bdd 100644
--- a/bank/src/main/kotlin/tech/libeufin/bank/CoreBankApi.kt
+++ b/bank/src/main/kotlin/tech/libeufin/bank/CoreBankApi.kt
@@ -135,41 +135,45 @@ private fun Routing.coreBankTokenApi(db: Database) {
}
}
+suspend fun createAccount(db: Database, ctx: BankConfig, req: RegisterAccountRequest, isAdmin: Boolean): Pair<AccountCreationResult, IbanPayTo> {
+ // Prohibit reserved usernames:
+ if (RESERVED_ACCOUNTS.contains(req.username))
+ throw conflict(
+ "Username '${req.username}' is reserved.",
+ TalerErrorCode.BANK_RESERVED_USERNAME_CONFLICT
+ )
+
+ if (req.debit_threshold != null && !isAdmin)
+ throw conflict(
+ "only admin account can choose the debit limit",
+ TalerErrorCode.BANK_NON_ADMIN_PATCH_DEBT_LIMIT
+ )
+
+
+ val internalPayto = req.internal_payto_uri ?: IbanPayTo(genIbanPaytoUri())
+ val res = db.account.create(
+ login = req.username,
+ name = req.name,
+ email = req.challenge_contact_data?.email,
+ phone = req.challenge_contact_data?.phone,
+ cashoutPayto = req.cashout_payto_uri,
+ password = req.password,
+ internalPaytoUri = internalPayto,
+ isPublic = req.is_public,
+ isTalerExchange = req.is_taler_exchange,
+ maxDebt = req.debit_threshold ?: ctx.defaultDebtLimit,
+ bonus = if (!req.is_taler_exchange) ctx.registrationBonus
+ else TalerAmount(0, 0, ctx.regionalCurrency),
+ checkPaytoIdempotent = req.internal_payto_uri != null
+ )
+ return Pair(res, internalPayto)
+}
+
private fun Routing.coreBankAccountsApi(db: Database, ctx: BankConfig) {
authAdmin(db, TokenScope.readwrite, !ctx.allowRegistration) {
post("/accounts") {
val req = call.receive<RegisterAccountRequest>()
- // Prohibit reserved usernames:
- if (RESERVED_ACCOUNTS.contains(req.username))
- throw conflict(
- "Username '${req.username}' is reserved.",
- TalerErrorCode.BANK_RESERVED_USERNAME_CONFLICT
- )
-
- if (req.debit_threshold != null && !isAdmin)
- throw conflict(
- "only admin account can choose the debit limit",
- TalerErrorCode.BANK_NON_ADMIN_PATCH_DEBT_LIMIT
- )
-
-
- val internalPayto = req.internal_payto_uri ?: IbanPayTo(genIbanPaytoUri())
- val result = db.account.create(
- login = req.username,
- name = req.name,
- email = req.challenge_contact_data?.email,
- phone = req.challenge_contact_data?.phone,
- cashoutPayto = req.cashout_payto_uri,
- password = req.password,
- internalPaytoUri = internalPayto,
- isPublic = req.is_public,
- isTalerExchange = req.is_taler_exchange,
- maxDebt = req.debit_threshold ?: ctx.defaultCustomerDebtLimit,
- bonus = if (!req.is_taler_exchange) ctx.registrationBonus
- else TalerAmount(0, 0, ctx.regionalCurrency),
- checkPaytoIdempotent = req.internal_payto_uri != null
- )
-
+ val (result, internalPayto) = createAccount(db, ctx, req, isAdmin);
when (result) {
AccountCreationResult.BonusBalanceInsufficient -> throw conflict(
"Insufficient admin funds to grant bonus",
diff --git a/bank/src/main/kotlin/tech/libeufin/bank/Main.kt b/bank/src/main/kotlin/tech/libeufin/bank/Main.kt
index 71edb958..a1e28cf9 100644
--- a/bank/src/main/kotlin/tech/libeufin/bank/Main.kt
+++ b/bank/src/main/kotlin/tech/libeufin/bank/Main.kt
@@ -339,27 +339,7 @@ class CreateAccount : CliktCommand("Create an account", name = "create-account")
val dbCfg = cfg.loadDbConfig()
val db = Database(dbCfg.dbConnStr, ctx.regionalCurrency, ctx.fiatCurrency)
runBlocking {
- if (RESERVED_ACCOUNTS.contains(json.username)) {
- throw Exception("Username '${json.username}' is reserved")
- }
-
- val internalPayto = json.internal_payto_uri ?: IbanPayTo(genIbanPaytoUri())
- val result = db.account.create(
- login = json.username,
- name = json.name,
- email = json.challenge_contact_data?.email,
- phone = json.challenge_contact_data?.phone,
- cashoutPayto = json.cashout_payto_uri,
- password = json.password,
- internalPaytoUri = internalPayto,
- isPublic = json.is_public,
- isTalerExchange = json.is_taler_exchange,
- maxDebt = ctx.defaultCustomerDebtLimit,
- bonus = if (!json.is_taler_exchange) ctx.registrationBonus
- else TalerAmount(0, 0, ctx.regionalCurrency),
- checkPaytoIdempotent = json.internal_payto_uri != null
- )
-
+ val (result, internalPayto) = createAccount(db, ctx, json, true);
when (result) {
AccountCreationResult.BonusBalanceInsufficient ->
throw Exception("Insufficient admin funds to grant bonus")
diff --git a/bank/src/main/kotlin/tech/libeufin/bank/helpers.kt b/bank/src/main/kotlin/tech/libeufin/bank/helpers.kt
index dc65fd44..2fdb957c 100644
--- a/bank/src/main/kotlin/tech/libeufin/bank/helpers.kt
+++ b/bank/src/main/kotlin/tech/libeufin/bank/helpers.kt
@@ -131,7 +131,7 @@ suspend fun maybeCreateAdminAccount(db: Database, ctx: BankConfig, pw: String? =
internalPaytoUri = IbanPayTo(genIbanPaytoUri()),
isPublic = false,
isTalerExchange = false,
- maxDebt = ctx.defaultAdminDebtLimit,
+ maxDebt = ctx.defaultDebtLimit,
bonus = TalerAmount(0, 0, ctx.regionalCurrency),
checkPaytoIdempotent = false
)
diff --git a/bank/src/test/kotlin/CoreBankApiTest.kt b/bank/src/test/kotlin/CoreBankApiTest.kt
index c880be59..dedca301 100644
--- a/bank/src/test/kotlin/CoreBankApiTest.kt
+++ b/bank/src/test/kotlin/CoreBankApiTest.kt
@@ -261,13 +261,15 @@ class CoreBankAccountsApiTest {
// Test account created with bonus
@Test
- fun createBonus() = bankSetup(conf = "test_bonus.conf") { _ ->
+ fun createBonus() = bankSetup(conf = "test_bonus.conf") { _ ->
val req = obj {
"username" to "foo"
"password" to "xyz"
"name" to "Mallory"
}
+ setMaxDebt("admin", "KUDOS:10000")
+
// Check ok
repeat(100) {
client.post("/accounts") {
diff --git a/bank/src/test/kotlin/RevenueApiTest.kt b/bank/src/test/kotlin/RevenueApiTest.kt
index 4432ce54..0a8a052a 100644
--- a/bank/src/test/kotlin/RevenueApiTest.kt
+++ b/bank/src/test/kotlin/RevenueApiTest.kt
@@ -32,7 +32,7 @@ class RevenueApiTest {
// GET /accounts/{USERNAME}/taler-revenue/history
@Test
fun history() = bankSetup {
- setMaxDebt("exchange", TalerAmount("KUDOS:1000000"))
+ setMaxDebt("exchange", "KUDOS:1000000")
authRoutine(HttpMethod.Get, "/accounts/merchant/taler-revenue/history")
historyRoutine<MerchantIncomingHistory>(
url = "/accounts/merchant/taler-revenue/history",
diff --git a/bank/src/test/kotlin/StatsTest.kt b/bank/src/test/kotlin/StatsTest.kt
index 98184805..981eb34d 100644
--- a/bank/src/test/kotlin/StatsTest.kt
+++ b/bank/src/test/kotlin/StatsTest.kt
@@ -33,9 +33,9 @@ import tech.libeufin.util.*
class StatsTest {
@Test
fun register() = bankSetup { db ->
- setMaxDebt("merchant", TalerAmount("KUDOS:1000"))
- setMaxDebt("exchange", TalerAmount("KUDOS:1000"))
- setMaxDebt("customer", TalerAmount("KUDOS:1000"))
+ setMaxDebt("merchant", "KUDOS:1000")
+ setMaxDebt("exchange", "KUDOS:1000")
+ setMaxDebt("customer", "KUDOS:1000")
suspend fun cashin(amount: String) {
db.conn { conn ->
diff --git a/bank/src/test/kotlin/WireGatewayApiTest.kt b/bank/src/test/kotlin/WireGatewayApiTest.kt
index 654cdcc5..65a890a9 100644
--- a/bank/src/test/kotlin/WireGatewayApiTest.kt
+++ b/bank/src/test/kotlin/WireGatewayApiTest.kt
@@ -50,7 +50,7 @@ class WireGatewayApiTest {
}.assertConflict(TalerErrorCode.BANK_UNALLOWED_DEBIT)
// Giving debt allowance and checking the OK case.
- setMaxDebt("exchange", TalerAmount("KUDOS:1000"))
+ setMaxDebt("exchange", "KUDOS:1000")
client.postA("/accounts/exchange/taler-wire-gateway/transfer") {
json(valid_req)
}.assertOk()
@@ -128,7 +128,7 @@ class WireGatewayApiTest {
@Test
fun historyIncoming() = bankSetup {
// Give Foo reasonable debt allowance:
- setMaxDebt("merchant", TalerAmount("KUDOS:1000"))
+ setMaxDebt("merchant", "KUDOS:1000")
authRoutine(HttpMethod.Get, "/accounts/merchant/taler-wire-gateway/history/incoming")
historyRoutine<IncomingHistory>(
url = "/accounts/exchange/taler-wire-gateway/history/incoming",
@@ -166,7 +166,7 @@ class WireGatewayApiTest {
*/
@Test
fun historyOutgoing() = bankSetup {
- setMaxDebt("exchange", TalerAmount("KUDOS:1000000"))
+ setMaxDebt("exchange", "KUDOS:1000000")
authRoutine(HttpMethod.Get, "/accounts/merchant/taler-wire-gateway/history/outgoing")
historyRoutine<OutgoingHistory>(
url = "/accounts/exchange/taler-wire-gateway/history/outgoing",
@@ -211,7 +211,7 @@ class WireGatewayApiTest {
}.assertConflict(TalerErrorCode.BANK_UNALLOWED_DEBIT)
// Giving debt allowance and checking the OK case.
- setMaxDebt("merchant", TalerAmount("KUDOS:1000"))
+ setMaxDebt("merchant", "KUDOS:1000")
client.postA("/accounts/exchange/taler-wire-gateway/admin/add-incoming") {
json(valid_req, deflate = true)
}.assertOk()
diff --git a/bank/src/test/kotlin/helpers.kt b/bank/src/test/kotlin/helpers.kt
index 7d65e2f8..00830bb6 100644
--- a/bank/src/test/kotlin/helpers.kt
+++ b/bank/src/test/kotlin/helpers.kt
@@ -138,7 +138,7 @@ fun dbSetup(lambda: suspend (Database) -> Unit) {
/* ----- Common actions ----- */
/** Set [account] debit threshold to [maxDebt] amount */
-suspend fun ApplicationTestBuilder.setMaxDebt(account: String, maxDebt: TalerAmount) {
+suspend fun ApplicationTestBuilder.setMaxDebt(account: String, maxDebt: String) {
client.patch("/accounts/$account") {
pwAuth("admin")
json { "debit_threshold" to maxDebt }
diff --git a/contrib/bank.conf b/contrib/bank.conf
index 7d6ca375..70b2690a 100644
--- a/contrib/bank.conf
+++ b/contrib/bank.conf
@@ -1,46 +1,43 @@
[libeufin-bank]
# Internal currency of the libeufin-bank
-#CURRENCY = KUDOS
+# CURRENCY = KUDOS
-# Default debt limit for newly created customer accounts Default is CURRENCY:0
-#DEFAULT_CUSTOMER_DEBT_LIMIT = KUDOS:200
-
-# Default debt limit of the admin. Typically higher, since sign-up bonuses and cashin are deducted from the admin account. Default is CURRENCY:0
-#DEFAULT_ADMIN_DEBT_LIMIT = KUDOS:20000000
+# Default debt limit for newly created accounts Default is CURRENCY:0
+# DEFAULT_DEBT_LIMIT = KUDOS:200
# Value of the registration bonus for new users. Default is CURRENCY:0
-#REGISTRATION_BONUS = KUDOS:100
+# REGISTRATION_BONUS = KUDOS:100
# Allow account registration by anyone.
-#ALLOW_REGISTRATION = yes
+# ALLOW_REGISTRATION = no
# Allow an account to delete itself
-#ALLOW_ACCOUNT_DELETION = yes
+# ALLOW_ACCOUNT_DELETION = no
# Enable regional currency conversion
-#ALLOW_CONVERSION = no
+# ALLOW_CONVERSION = no
# External currency used during cashin and cashout
-#FIAT_CURRENCY = EUR
+# FIAT_CURRENCY = EUR
# Path to TAN challenge transmission script via sms. If not specified, this TAN channel will not be supported.
-#TAN_SMS =
+# TAN_SMS =
# Path to TAN challenge transmission script via email. If not specified, this TAN channel will not be supported.
-#TAN_EMAIL =
+# TAN_EMAIL =
# How "libeufin-bank serve" serves its API, this can either be tcp or unix
-#SERVE = tcp
+# SERVE = tcp
# Port on which the HTTP server listens, e.g. 9967. Only used if SERVE is tcp.
-#PORT = 8080
+# PORT = 8080
# Which unix domain path should we bind to? Only used if SERVE is unix.
-#UNIXPATH = libeufin-bank.sock
+# UNIXPATH = libeufin-bank.sock
# What should be the file access permissions for UNIXPATH? Only used if SERVE is unix.
-#UNIXPATH_MODE = 660
+# UNIXPATH_MODE = 660
# Path to spa files
diff --git a/debian/etc/libeufin/libeufin-bank.conf b/debian/etc/libeufin/libeufin-bank.conf
index 597ceb7b..71fb9fa4 100644
--- a/debian/etc/libeufin/libeufin-bank.conf
+++ b/debian/etc/libeufin/libeufin-bank.conf
@@ -5,17 +5,20 @@
# Internal currency of the libeufin-bank
CURRENCY = KUDOS
-# Default debt limit for newly created customer accounts
-# DEFAULT_CUSTOMER_DEBT_LIMIT = KUDOS:0
+# Default debt limit for newly created accounts
+# DEFAULT_DEBT_LIMIT = KUDOS:0
-# Value of the registration bonus for new users. Default is "CURRENCY:0"
+# Value of the registration bonus for new users
# REGISTRATION_BONUS = KUDOS:0
-# Allow account registration by anyone.
-# ALLOW_REGISTRATION = yes
+# Allow account registration by anyone
+# ALLOW_REGISTRATION = no
# Allow an account to delete itself
-# ALLOW_ACCOUNT_DELETION = yes
+# ALLOW_ACCOUNT_DELETION = no
+
+# Enable regional currency conversion
+# ALLOW_CONVERSION = no
# Path to TAN challenge transmission script via sms. If not specified, this TAN channel wil be unuspported.
TAN_SMS =
diff --git a/integration/conf/integration.conf b/integration/conf/integration.conf
index 07feee27..55a3d871 100644
--- a/integration/conf/integration.conf
+++ b/integration/conf/integration.conf
@@ -1,7 +1,5 @@
[libeufin-bank]
CURRENCY = KUDOS
-DEFAULT_CUSTOMER_DEBT_LIMIT = KUDOS:100
-DEFAULT_ADMIN_DEBT_LIMIT = KUDOS:10000
SUGGESTED_WITHDRAWAL_EXCHANGE = https://exchange.example.com
ALLOW_REGISTRATION = yes
ALLOW_ACCOUNT_DELETION = yes
diff --git a/integration/test/IntegrationTest.kt b/integration/test/IntegrationTest.kt
index 315e230e..e0bc237a 100644
--- a/integration/test/IntegrationTest.kt
+++ b/integration/test/IntegrationTest.kt
@@ -103,12 +103,14 @@ class IntegrationTest {
// Create user
client.post("http://0.0.0.0:8080/accounts") {
+ basicAuth("admin", "password")
json {
"username" to "customer"
"password" to "password"
"name" to "JohnSmith"
"internal_payto_uri" to userPayTo
"cashout_payto_uri" to fiatPayTo
+ "debit_threshold" to "KUDOS:100"
"challenge_contact_data" to obj {
"phone" to "+99"
}
@@ -132,6 +134,14 @@ class IntegrationTest {
}
}.assertNoContent()
+ // Set admin debit threshold
+ client.patch("http://0.0.0.0:8080/accounts/admin") {
+ basicAuth("admin", "password")
+ json {
+ "debit_threshold" to "KUDOS:1000"
+ }
+ }.assertNoContent()
+
// Cashin
repeat(3) { i ->
val reservePub = randBytes(32);