summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAntoine A <>2023-12-11 15:06:23 +0000
committerAntoine A <>2023-12-11 15:06:23 +0000
commit27ac4e561fddd4f59f84bf06642a1d3f8eb11d6b (patch)
tree3d22a03e9369186aae9c8f041f4ca50754fc2c98
parent117fa34b78db0af0dcbcd281d17b7c0e0a5294cc (diff)
downloadlibeufin-27ac4e561fddd4f59f84bf06642a1d3f8eb11d6b.tar.gz
libeufin-27ac4e561fddd4f59f84bf06642a1d3f8eb11d6b.tar.bz2
libeufin-27ac4e561fddd4f59f84bf06642a1d3f8eb11d6b.zip
Restrict contact data patch to admin
-rw-r--r--bank/src/main/kotlin/tech/libeufin/bank/CoreBankApi.kt4
-rw-r--r--bank/src/main/kotlin/tech/libeufin/bank/Main.kt3
-rw-r--r--bank/src/main/kotlin/tech/libeufin/bank/db/AccountDAO.kt13
-rw-r--r--bank/src/test/kotlin/CoreBankApiTest.kt31
-rw-r--r--bank/src/test/kotlin/helpers.kt3
-rw-r--r--util/src/main/kotlin/TalerErrorCode.kt8
6 files changed, 51 insertions, 11 deletions
diff --git a/bank/src/main/kotlin/tech/libeufin/bank/CoreBankApi.kt b/bank/src/main/kotlin/tech/libeufin/bank/CoreBankApi.kt
index caac34b0..248a8a83 100644
--- a/bank/src/main/kotlin/tech/libeufin/bank/CoreBankApi.kt
+++ b/bank/src/main/kotlin/tech/libeufin/bank/CoreBankApi.kt
@@ -272,6 +272,10 @@ private fun Routing.coreBankAccountsApi(db: Database, ctx: BankConfig) {
"non-admin user cannot change their debt limit",
TalerErrorCode.BANK_NON_ADMIN_PATCH_DEBT_LIMIT
)
+ AccountPatchResult.NonAdminContact -> throw conflict(
+ "non-admin user cannot change their contact info",
+ TalerErrorCode.BANK_NON_ADMIN_PATCH_CONTACT
+ )
}
}
patch("/accounts/{USERNAME}/auth") {
diff --git a/bank/src/main/kotlin/tech/libeufin/bank/Main.kt b/bank/src/main/kotlin/tech/libeufin/bank/Main.kt
index 5987fbcc..908c3234 100644
--- a/bank/src/main/kotlin/tech/libeufin/bank/Main.kt
+++ b/bank/src/main/kotlin/tech/libeufin/bank/Main.kt
@@ -392,7 +392,8 @@ class EditAccount : CliktCommand(
throw Exception("Account '$username' not found")
AccountPatchResult.NonAdminName,
AccountPatchResult.NonAdminCashout,
- AccountPatchResult.NonAdminDebtLimit -> {
+ AccountPatchResult.NonAdminDebtLimit,
+ AccountPatchResult.NonAdminContact -> {
// Unreachable as we edit account as admin
}
}
diff --git a/bank/src/main/kotlin/tech/libeufin/bank/db/AccountDAO.kt b/bank/src/main/kotlin/tech/libeufin/bank/db/AccountDAO.kt
index c0dbe66a..276e5e56 100644
--- a/bank/src/main/kotlin/tech/libeufin/bank/db/AccountDAO.kt
+++ b/bank/src/main/kotlin/tech/libeufin/bank/db/AccountDAO.kt
@@ -199,6 +199,7 @@ class AccountDAO(private val db: Database) {
NonAdminName,
NonAdminCashout,
NonAdminDebtLimit,
+ NonAdminContact,
Success
}
@@ -218,6 +219,8 @@ class AccountDAO(private val db: Database) {
val checkName = !isAdmin && !allowEditName && name != null
val checkCashout = !isAdmin && !allowEditCashout && cashoutPayto.isSome()
val checkDebtLimit = !isAdmin && debtLimit != null
+ val checkPhone = !isAdmin && phone.isSome()
+ val checkEmail = !isAdmin && email.isSome()
// Get user ID and check reconfig rights
val customer_id = conn.prepareStatement("""
@@ -226,6 +229,8 @@ class AccountDAO(private val db: Database) {
,(${ if (checkName) "name != ? " else "false" }) as name_change
,(${ if (checkCashout) "cashout_payto IS DISTINCT FROM ?" else "false" }) as cashout_change
,(${ if (checkDebtLimit) "max_debt != (?, ?)::taler_amount" else "false" }) as debt_limit_change
+ ,(${ if (checkPhone) "phone IS DISTINCT FROM ?" else "false" }) as phone_change
+ ,(${ if (checkEmail) "email IS DISTINCT FROM ?" else "false" }) as email_change
FROM customers
JOIN bank_accounts
ON customer_id=owning_customer_id
@@ -242,6 +247,12 @@ class AccountDAO(private val db: Database) {
setLong(idx, debtLimit!!.value); idx++
setInt(idx, debtLimit.frac); idx++
}
+ if (checkPhone) {
+ setString(idx, phone.get()); idx++
+ }
+ if (checkEmail) {
+ setString(idx, email.get()); idx++
+ }
setString(idx, login)
executeQuery().use {
when {
@@ -249,6 +260,8 @@ class AccountDAO(private val db: Database) {
it.getBoolean("name_change") -> return@transaction AccountPatchResult.NonAdminName
it.getBoolean("cashout_change") -> return@transaction AccountPatchResult.NonAdminCashout
it.getBoolean("debt_limit_change") -> return@transaction AccountPatchResult.NonAdminDebtLimit
+ it.getBoolean("phone_change") -> return@transaction AccountPatchResult.NonAdminContact
+ it.getBoolean("email_change") -> return@transaction AccountPatchResult.NonAdminContact
else -> it.getLong("customer_id")
}
}
diff --git a/bank/src/test/kotlin/CoreBankApiTest.kt b/bank/src/test/kotlin/CoreBankApiTest.kt
index 85a780dc..c9328f90 100644
--- a/bank/src/test/kotlin/CoreBankApiTest.kt
+++ b/bank/src/test/kotlin/CoreBankApiTest.kt
@@ -376,16 +376,23 @@ class CoreBankAccountsApiTest {
client.deleteA("/accounts/exchange").assertNoContent()
}
- suspend fun ApplicationTestBuilder.checkAdminOnly(req: JsonElement, error: TalerErrorCode) {
- // Checking ordinary user doesn't get to patch
+ suspend fun ApplicationTestBuilder.checkAdminOnly(
+ req: JsonElement,
+ error: TalerErrorCode
+ ) {
+ // Check restricted
client.patchA("/accounts/merchant") {
json(req)
}.assertConflict(error)
- // Finally checking that admin does get to patch
+ // Check admin always can
client.patch("/accounts/merchant") {
pwAuth("admin")
json(req)
}.assertNoContent()
+ // Check idempotent
+ client.patchA("/accounts/merchant") {
+ json(req)
+ }.assertNoContent()
}
// PATCH /accounts/USERNAME
@@ -397,10 +404,6 @@ class CoreBankAccountsApiTest {
val cashout = IbanPayTo(genIbanPaytoUri())
val req = obj {
"cashout_payto_uri" to cashout.canonical
- "contact_data" to obj {
- "phone" to "+99"
- "email" to "foo@example.com"
- }
"name" to "Roger"
"is_public" to true
}
@@ -416,6 +419,14 @@ class CoreBankAccountsApiTest {
obj(req) { "debit_threshold" to "KUDOS:100" },
TalerErrorCode.BANK_NON_ADMIN_PATCH_DEBT_LIMIT
)
+ checkAdminOnly(
+ obj(req) { "contact_data" to obj { "phone" to "+99" } },
+ TalerErrorCode.BANK_NON_ADMIN_PATCH_CONTACT
+ )
+ checkAdminOnly(
+ obj(req) { "contact_data" to obj { "email" to "foo@example.com" } },
+ TalerErrorCode.BANK_NON_ADMIN_PATCH_CONTACT
+ )
// Check currency
client.patch("/accounts/merchant") {
@@ -975,7 +986,8 @@ class CoreBankCashoutApiTest {
client.postA("/accounts/customer/cashouts") {
json(req)
}.assertConflict(TalerErrorCode.BANK_MISSING_TAN_INFO)
- client.patchA("/accounts/customer") {
+ client.patch("/accounts/customer") {
+ pwAuth("admin")
json {
"contact_data" to obj {
"phone" to "+99"
@@ -1132,7 +1144,8 @@ class CoreBankCashoutApiTest {
fun confirm() = bankSetup { _ ->
authRoutine(HttpMethod.Post, "/accounts/merchant/cashouts/42/confirm")
- client.patchA("/accounts/customer") {
+ client.patch("/accounts/customer") {
+ pwAuth("admin")
json {
"contact_data" to obj {
"phone" to "+99"
diff --git a/bank/src/test/kotlin/helpers.kt b/bank/src/test/kotlin/helpers.kt
index c298fcb2..eacd39ff 100644
--- a/bank/src/test/kotlin/helpers.kt
+++ b/bank/src/test/kotlin/helpers.kt
@@ -235,7 +235,8 @@ suspend fun ApplicationTestBuilder.withdrawal(amount: String) {
}
suspend fun ApplicationTestBuilder.fillCashoutInfo(account: String) {
- client.patchA("/accounts/$account") {
+ client.patch("/accounts/$account") {
+ pwAuth("admin")
json {
"cashout_payto_uri" to unknownPayto
"contact_data" to obj {
diff --git a/util/src/main/kotlin/TalerErrorCode.kt b/util/src/main/kotlin/TalerErrorCode.kt
index ff9dce29..d7f11abd 100644
--- a/util/src/main/kotlin/TalerErrorCode.kt
+++ b/util/src/main/kotlin/TalerErrorCode.kt
@@ -3482,6 +3482,14 @@ enum class TalerErrorCode(val code: Int) {
/**
+ * A non-admin user has tried to change their contact info.
+ * Returned with an HTTP status code of #MHD_HTTP_CONFLICT (409).
+ * (A value of 0 indicates that the error is generated client-side).
+ */
+ BANK_NON_ADMIN_PATCH_CONTACT(5141),
+
+
+ /**
* The sync service failed find the account in its database.
* Returned with an HTTP status code of #MHD_HTTP_NOT_FOUND (404).
* (A value of 0 indicates that the error is generated client-side).