diff options
author | Antoine A <> | 2023-12-11 15:06:23 +0000 |
---|---|---|
committer | Antoine A <> | 2023-12-11 15:06:23 +0000 |
commit | 27ac4e561fddd4f59f84bf06642a1d3f8eb11d6b (patch) | |
tree | 3d22a03e9369186aae9c8f041f4ca50754fc2c98 | |
parent | 117fa34b78db0af0dcbcd281d17b7c0e0a5294cc (diff) | |
download | libeufin-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.kt | 4 | ||||
-rw-r--r-- | bank/src/main/kotlin/tech/libeufin/bank/Main.kt | 3 | ||||
-rw-r--r-- | bank/src/main/kotlin/tech/libeufin/bank/db/AccountDAO.kt | 13 | ||||
-rw-r--r-- | bank/src/test/kotlin/CoreBankApiTest.kt | 31 | ||||
-rw-r--r-- | bank/src/test/kotlin/helpers.kt | 3 | ||||
-rw-r--r-- | util/src/main/kotlin/TalerErrorCode.kt | 8 |
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). |