[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]
[libeufin] branch master updated (61c49361 -> 1e3e0927)
From: |
gnunet |
Subject: |
[libeufin] branch master updated (61c49361 -> 1e3e0927) |
Date: |
Tue, 14 Nov 2023 00:38:07 +0100 |
This is an automated email from the git hooks/post-receive script.
antoine pushed a change to branch master
in repository libeufin.
from 61c49361 rm idea files
new cb7094fe Improve accounts API
new 1e3e0927 Improve cashout API
The 2 revisions listed above as "new" are entirely new to this
repository and will be described in separate emails. The revisions
listed as "add" were already present in the repository and have only
been added to this reference.
Summary of changes:
.../main/kotlin/tech/libeufin/bank/CoreBankApi.kt | 41 ++++++++++-----
bank/src/main/kotlin/tech/libeufin/bank/Main.kt | 2 +-
.../main/kotlin/tech/libeufin/bank/TalerMessage.kt | 3 +-
.../main/kotlin/tech/libeufin/bank/db/Database.kt | 40 +++++++++++----
bank/src/test/kotlin/CoreBankApiTest.kt | 60 +++++++++++++++++-----
util/src/main/kotlin/TalerErrorCode.kt | 48 +++++++++++++++++
6 files changed, 156 insertions(+), 38 deletions(-)
diff --git a/bank/src/main/kotlin/tech/libeufin/bank/CoreBankApi.kt
b/bank/src/main/kotlin/tech/libeufin/bank/CoreBankApi.kt
index ad87078d..165850dd 100644
--- a/bank/src/main/kotlin/tech/libeufin/bank/CoreBankApi.kt
+++ b/bank/src/main/kotlin/tech/libeufin/bank/CoreBankApi.kt
@@ -221,7 +221,10 @@ private fun Routing.coreBankAccountsMgmtApi(db: Database,
ctx: BankConfig) {
req.debit_threshold?.run { ctx.checkRegionalCurrency(this) }
if (req.is_taler_exchange != null && username == "admin")
- throw forbidden("admin account cannot be an exchange")
+ throw conflict(
+ "admin account cannot be an exchange",
+ TalerErrorCode.BANK_PATCH_ADMIN_EXCHANGE
+ )
val res = db.accountReconfig(
login = username,
@@ -239,27 +242,38 @@ private fun Routing.coreBankAccountsMgmtApi(db: Database,
ctx: BankConfig) {
"Account '$username' not found",
TalerErrorCode.BANK_UNKNOWN_ACCOUNT
)
- CustomerPatchResult.CONFLICT_LEGAL_NAME ->
- throw forbidden("non-admin user cannot change their legal
name")
- CustomerPatchResult.CONFLICT_DEBT_LIMIT ->
- throw forbidden("non-admin user cannot change their debt
limit")
+ CustomerPatchResult.CONFLICT_LEGAL_NAME -> throw conflict(
+ "non-admin user cannot change their legal name",
+ TalerErrorCode.BANK_NON_ADMIN_PATCH_LEGAL_NAME
+ )
+ CustomerPatchResult.CONFLICT_DEBT_LIMIT -> throw conflict(
+ "non-admin user cannot change their debt limit",
+ TalerErrorCode.BANK_NON_ADMIN_PATCH_DEBT_LIMIT
+ )
}
}
- }
- auth(db, TokenScope.readwrite) {
patch("/accounts/{USERNAME}/auth") {
val req = call.receive<AccountPasswordChange>()
- val hashedPassword = CryptoUtil.hashpw(req.new_password)
- if (!db.customerChangePassword(username, hashedPassword))
- throw notFound(
+ if (!isAdmin && req.old_password == null) {
+ throw conflict(
+ "non-admin user cannot change password without providing
old password",
+ TalerErrorCode.BANK_NON_ADMIN_PATCH_MISSING_OLD_PASSWORD
+ )
+ }
+ when (db.accountReconfigPassword(username, req.new_password,
req.old_password)) {
+ CustomerPatchAuthResult.SUCCESS ->
call.respond(HttpStatusCode.NoContent)
+ CustomerPatchAuthResult.ACCOUNT_NOT_FOUND -> throw notFound(
"Account '$username' not found",
TalerErrorCode.BANK_UNKNOWN_ACCOUNT
)
- call.respond(HttpStatusCode.NoContent)
+ CustomerPatchAuthResult.CONFLICT_BAD_PASSWORD -> throw
conflict(
+ "old password does not match",
+ TalerErrorCode.BANK_PATCH_BAD_OLD_PASSWORD
+ )
+ }
}
}
get("/public-accounts") {
- // no authentication here.
val publicAccounts = db.accountsGetPublic(ctx.currency)
if (publicAccounts.isEmpty()) {
call.respond(HttpStatusCode.NoContent)
@@ -538,8 +552,7 @@ private fun Routing.coreBankCashoutApi(db: Database, ctx:
BankConfig) = conditio
process.exitValue()
}
if (exitValue != 0) {
- throw libeufinError(
- HttpStatusCode.BadGateway,
+ throw conflict(
"Tan channel script failure with exit value
$exitValue",
TalerErrorCode.BANK_TAN_CHANNEL_SCRIPT_FAILED
)
diff --git a/bank/src/main/kotlin/tech/libeufin/bank/Main.kt
b/bank/src/main/kotlin/tech/libeufin/bank/Main.kt
index 00094213..8bb421c7 100644
--- a/bank/src/main/kotlin/tech/libeufin/bank/Main.kt
+++ b/bank/src/main/kotlin/tech/libeufin/bank/Main.kt
@@ -331,7 +331,7 @@ class ChangePw : CliktCommand("Change account password",
name = "passwd") {
if (!maybeCreateAdminAccount(db, ctx)) // logs provided by the
helper
exitProcess(1)
- if (!db.customerChangePassword(account,
CryptoUtil.hashpw(password))) {
+ if (db.accountReconfigPassword(account, password, null) !=
CustomerPatchAuthResult.SUCCESS) {
println("password change failed")
exitProcess(1)
} else {
diff --git a/bank/src/main/kotlin/tech/libeufin/bank/TalerMessage.kt
b/bank/src/main/kotlin/tech/libeufin/bank/TalerMessage.kt
index c8d176fe..b91efe7a 100644
--- a/bank/src/main/kotlin/tech/libeufin/bank/TalerMessage.kt
+++ b/bank/src/main/kotlin/tech/libeufin/bank/TalerMessage.kt
@@ -609,5 +609,6 @@ data class PublicAccount(
*/
@Serializable
data class AccountPasswordChange(
- val new_password: String
+ val new_password: String,
+ val old_password: String? = null
)
\ No newline at end of file
diff --git a/bank/src/main/kotlin/tech/libeufin/bank/db/Database.kt
b/bank/src/main/kotlin/tech/libeufin/bank/db/Database.kt
index 2cf5e7e5..863347e1 100644
--- a/bank/src/main/kotlin/tech/libeufin/bank/db/Database.kt
+++ b/bank/src/main/kotlin/tech/libeufin/bank/db/Database.kt
@@ -110,15 +110,6 @@ class Database(dbConfig: String, internal val
bankCurrency: String, internal val
}
}
- suspend fun customerChangePassword(customerName: String, passwordHash:
String): Boolean = conn { conn ->
- val stmt = conn.prepareStatement("""
- UPDATE customers SET password_hash=? where login=?
- """)
- stmt.setString(1, passwordHash)
- stmt.setString(2, customerName)
- stmt.executeUpdateCheck()
- }
-
suspend fun customerPasswordHashFromLogin(login: String): String? = conn {
conn ->
val stmt = conn.prepareStatement("""
SELECT password_hash FROM customers WHERE login=?
@@ -438,6 +429,30 @@ class Database(dbConfig: String, internal val
bankCurrency: String, internal val
}
}
+ suspend fun accountReconfigPassword(login: String, newPw: String, oldPw:
String?): CustomerPatchAuthResult = conn {
+ it.transaction { conn ->
+ val currentPwh = conn.prepareStatement("""
+ SELECT password_hash FROM customers WHERE login=?
+ """).run {
+ setString(1, login)
+ oneOrNull { it.getString(1) }
+ }
+ if (currentPwh == null) {
+ CustomerPatchAuthResult.ACCOUNT_NOT_FOUND
+ } else if (oldPw != null && !CryptoUtil.checkpw(oldPw,
currentPwh)) {
+ CustomerPatchAuthResult.CONFLICT_BAD_PASSWORD
+ } else {
+ val stmt = conn.prepareStatement("""
+ UPDATE customers SET password_hash=? where login=?
+ """)
+ stmt.setString(1, CryptoUtil.hashpw(newPw))
+ stmt.setString(2, login)
+ stmt.executeUpdateCheck()
+ CustomerPatchAuthResult.SUCCESS
+ }
+ }
+ }
+
/**
* Gets the list of public accounts in the system.
* internalCurrency is the bank's currency and loginFilter is
@@ -943,6 +958,13 @@ enum class CustomerPatchResult {
SUCCESS
}
+/** Result status of customer account auth patch */
+enum class CustomerPatchAuthResult {
+ ACCOUNT_NOT_FOUND,
+ CONFLICT_BAD_PASSWORD,
+ SUCCESS
+}
+
/** Result status of customer account deletion */
enum class CustomerDeletionResult {
SUCCESS,
diff --git a/bank/src/test/kotlin/CoreBankApiTest.kt
b/bank/src/test/kotlin/CoreBankApiTest.kt
index b0d4289a..e14f361d 100644
--- a/bank/src/test/kotlin/CoreBankApiTest.kt
+++ b/bank/src/test/kotlin/CoreBankApiTest.kt
@@ -352,12 +352,12 @@ class CoreBankAccountsMgmtApiTest {
jsonBody(req)
}.assertNoContent()
- suspend fun checkAdminOnly(req: JsonElement) {
+ suspend fun checkAdminOnly(req: JsonElement, error: TalerErrorCode) {
// Checking ordinary user doesn't get to patch
client.patch("/accounts/merchant") {
basicAuth("merchant", "merchant-password")
jsonBody(req)
- }.assertForbidden()
+ }.assertConflict(error)
// Finally checking that admin does get to patch
client.patch("/accounts/merchant") {
basicAuth("admin", "admin-password")
@@ -365,14 +365,20 @@ class CoreBankAccountsMgmtApiTest {
}.assertNoContent()
}
- checkAdminOnly(json(req) { "name" to "Another Foo" })
- checkAdminOnly(json(req) { "debit_threshold" to "KUDOS:100" })
+ checkAdminOnly(
+ json(req) { "name" to "Another Foo" },
+ TalerErrorCode.BANK_NON_ADMIN_PATCH_LEGAL_NAME
+ )
+ checkAdminOnly(
+ json(req) { "debit_threshold" to "KUDOS:100" },
+ TalerErrorCode.BANK_NON_ADMIN_PATCH_DEBT_LIMIT
+ )
// Check admin account cannot be exchange
client.patch("/accounts/admin") {
basicAuth("admin", "admin-password")
jsonBody { "is_taler_exchange" to true }
- }.assertForbidden()
+ }.assertConflict(TalerErrorCode.BANK_PATCH_ADMIN_EXCHANGE)
// But we can change its debt limit
client.patch("/accounts/admin") {
basicAuth("admin", "admin-password")
@@ -402,21 +408,49 @@ class CoreBankAccountsMgmtApiTest {
@Test
fun passwordChangeTest() = bankSetup { _ ->
// Changing the password.
- client.patch("/accounts/merchant/auth") {
- basicAuth("merchant", "merchant-password")
+ client.patch("/accounts/customer/auth") {
+ basicAuth("customer", "customer-password")
jsonBody {
+ "old_password" to "customer-password"
"new_password" to "new-password"
}
}.assertNoContent()
// Previous password should fail.
- client.patch("/accounts/merchant/auth") {
- basicAuth("merchant", "merchant-password")
+ client.patch("/accounts/customer/auth") {
+ basicAuth("customer", "customer-password")
}.assertUnauthorized()
// New password should succeed.
- client.patch("/accounts/merchant/auth") {
- basicAuth("merchant", "new-password")
+ client.patch("/accounts/customer/auth") {
+ basicAuth("customer", "new-password")
jsonBody {
- "new_password" to "merchant-password"
+ "old_password" to "new-password"
+ "new_password" to "customer-password"
+ }
+ }.assertNoContent()
+
+
+ // Check require test old password
+ client.patch("/accounts/customer/auth") {
+ basicAuth("customer", "customer-password")
+ jsonBody {
+ "old_password" to "bad-password"
+ "new_password" to "new-password"
+ }
+ }.assertConflict(TalerErrorCode.BANK_PATCH_BAD_OLD_PASSWORD)
+
+ // Check require old password for user
+ client.patch("/accounts/customer/auth") {
+ basicAuth("customer", "customer-password")
+ jsonBody {
+ "new_password" to "new-password"
+ }
+
}.assertConflict(TalerErrorCode.BANK_NON_ADMIN_PATCH_MISSING_OLD_PASSWORD)
+
+ // Check admin
+ client.patch("/accounts/customer/auth") {
+ basicAuth("admin", "admin-password")
+ jsonBody {
+ "new_password" to "new-password"
}
}.assertNoContent()
}
@@ -1039,7 +1073,7 @@ class CoreBankCashoutApiTest {
jsonBody(req) {
"tan_channel" to "email"
}
- }.assertStatus(HttpStatusCode.BadGateway,
TalerErrorCode.BANK_TAN_CHANNEL_SCRIPT_FAILED)
+ }.assertConflict(TalerErrorCode.BANK_TAN_CHANNEL_SCRIPT_FAILED)
// Check OK
client.post("/accounts/customer/cashouts") {
diff --git a/util/src/main/kotlin/TalerErrorCode.kt
b/util/src/main/kotlin/TalerErrorCode.kt
index 126b899f..70f08e34 100644
--- a/util/src/main/kotlin/TalerErrorCode.kt
+++ b/util/src/main/kotlin/TalerErrorCode.kt
@@ -665,6 +665,14 @@ enum class TalerErrorCode(val code: Int) {
EXCHANGE_GENERIC_AML_FROZEN(1036),
+ /**
+ * The exchange failed to start a KYC attribute conversion helper process.
It is likely configured incorrectly.
+ * Returned with an HTTP status code of #MHD_HTTP_INTERNAL_SERVER_ERROR
(500).
+ * (A value of 0 indicates that the error is generated client-side).
+ */
+ EXCHANGE_GENERIC_KYC_CONVERTER_FAILED(1037),
+
+
/**
* The exchange did not find information about the specified transaction in
the database.
* Returned with an HTTP status code of #MHD_HTTP_NOT_FOUND (404).
@@ -3425,6 +3433,46 @@ enum class TalerErrorCode(val code: Int) {
BANK_TAN_CHALLENGE_FAILED(5134),
+ /**
+ * A non-admin user has tried to change their legal name.
+ * 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_LEGAL_NAME(5135),
+
+
+ /**
+ * A non-admin user has tried to change their debt limit.
+ * 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_DEBT_LIMIT(5136),
+
+
+ /**
+ * A non-admin user has tried to change their password whihout providing the
current one.
+ * 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_MISSING_OLD_PASSWORD(5137),
+
+
+ /**
+ * Provided old password does not match current password.
+ * Returned with an HTTP status code of #MHD_HTTP_CONFLICT (409).
+ * (A value of 0 indicates that the error is generated client-side).
+ */
+ BANK_PATCH_BAD_OLD_PASSWORD(5138),
+
+
+ /**
+ * An admin user has tried to become an exchange.
+ * Returned with an HTTP status code of #MHD_HTTP_CONFLICT (409).
+ * (A value of 0 indicates that the error is generated client-side).
+ */
+ BANK_PATCH_ADMIN_EXCHANGE(5139),
+
+
/**
* The sync service failed find the account in its database.
* Returned with an HTTP status code of #MHD_HTTP_NOT_FOUND (404).
--
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 (61c49361 -> 1e3e0927),
gnunet <=