[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]
[libeufin] branch master updated: Progress with PATCH /accounts/{USERNAM
From: |
gnunet |
Subject: |
[libeufin] branch master updated: Progress with PATCH /accounts/{USERNAME}. |
Date: |
Tue, 03 Oct 2023 15:43:01 +0200 |
This is an automated email from the git hooks/post-receive script.
ms pushed a commit to branch master
in repository libeufin.
The following commit(s) were added to refs/heads/master by this push:
new 73bb6bfa Progress with PATCH /accounts/{USERNAME}.
73bb6bfa is described below
commit 73bb6bfaf25393d125bfafb37bae03df95592510
Author: MS <ms@taler.net>
AuthorDate: Tue Oct 3 15:41:52 2023 +0200
Progress with PATCH /accounts/{USERNAME}.
---
.../main/kotlin/tech/libeufin/bank/BankMessages.kt | 14 +++
.../tech/libeufin/bank/CorebankApiHandlers.kt | 99 ++++++++++++++++------
.../tech/libeufin/bank/WireGatewayApiHandlers.kt | 14 +--
bank/src/main/kotlin/tech/libeufin/bank/helpers.kt | 3 +-
4 files changed, 98 insertions(+), 32 deletions(-)
diff --git a/bank/src/main/kotlin/tech/libeufin/bank/BankMessages.kt
b/bank/src/main/kotlin/tech/libeufin/bank/BankMessages.kt
index 15188d41..a42cb1f6 100644
--- a/bank/src/main/kotlin/tech/libeufin/bank/BankMessages.kt
+++ b/bank/src/main/kotlin/tech/libeufin/bank/BankMessages.kt
@@ -668,7 +668,21 @@ data class PublicAccount(
val account_name: String
)
+/**
+ * Request of PATCH /accounts/{USERNAME}/auth
+ */
@Serializable
data class AccountPasswordChange(
val new_password: String
)
+
+/**
+ * Request of PATCH /accounts/{USERNAME}
+ */
+@Serializable
+data class AccountReconfiguration(
+ val challenge_contact_data: ChallengeContactData?,
+ val cashout_address: String?,
+ val name: String?,
+ val is_exchange: Boolean
+)
\ No newline at end of file
diff --git a/bank/src/main/kotlin/tech/libeufin/bank/CorebankApiHandlers.kt
b/bank/src/main/kotlin/tech/libeufin/bank/CorebankApiHandlers.kt
index a6a4f66f..9b75f874 100644
--- a/bank/src/main/kotlin/tech/libeufin/bank/CorebankApiHandlers.kt
+++ b/bank/src/main/kotlin/tech/libeufin/bank/CorebankApiHandlers.kt
@@ -203,7 +203,7 @@ fun Routing.accountsMgmtHandlers(db: Database, ctx:
BankApplicationContext) {
}
throw LibeufinBankException(
httpStatus = HttpStatusCode.Conflict, talerError = TalerError(
- code = GENERIC_UNDEFINED, // GANA needs this.
+ code = GENERIC_UNDEFINED, // FIXME: provide appropriate EC.
hint = "Idempotency check failed."
)
)
@@ -261,18 +261,16 @@ fun Routing.accountsMgmtHandlers(db: Database, ctx:
BankApplicationContext) {
}
get("/accounts/{USERNAME}") {
val c = call.authenticateBankRequest(db, TokenScope.readonly) ?: throw
unauthorized("Login failed")
- val resourceName = call.maybeUriComponent("USERNAME") ?: throw
badRequest(
- hint = "No username found in the URI", talerErrorCode =
TalerErrorCode.TALER_EC_GENERIC_PARAMETER_MISSING
- ) // Checking resource name only if Basic auth was used. Successful
tokens do not need this check, they just pass.
- if (((c.login != resourceName) && (c.login != "admin")) &&
(call.getAuthToken() == null)) throw forbidden("No rights on the resource.")
- val customerData = db.customerGetFromLogin(c.login)
- ?: throw internalServerError("Customer '${c.login} despite being
authenticated.'")
- val customerInternalId = customerData.dbRowId
- ?: throw internalServerError("Customer '${c.login} had no row ID
despite it was found in the database.'")
- val bankAccountData = db.bankAccountGetFromOwnerId(customerInternalId)
- ?: throw internalServerError("Customer '${c.login} had no bank
account despite they are customer.'")
+ val resourceName = call.expectUriComponent("USERNAME")
+ if (!resourceName.canI(c, withAdmin = true)) throw forbidden()
+ val customerData = db.customerGetFromLogin(resourceName) ?: throw
notFound(
+ "Customer '$resourceName' not found in the database.",
+ talerEc = TalerErrorCode.TALER_EC_END
+ )
+ val bankAccountData =
db.bankAccountGetFromOwnerId(customerData.expectRowId())
+ ?: throw internalServerError("Customer '$resourceName' had no bank
account despite they are customer.'")
val balance = Balance(
- amount = bankAccountData.balance ?: throw
internalServerError("Account '${c.login}' lacks balance!"),
+ amount = bankAccountData.balance ?: throw
internalServerError("Account '${customerData.login}' lacks balance!"),
credit_debit_indicator = if (bankAccountData.hasDebt) {
CorebankCreditDebitInfo.debit
} else {
@@ -329,17 +327,58 @@ fun Routing.accountsMgmtHandlers(db: Database, ctx:
BankApplicationContext) {
if (!accountName.canI(c, withAdmin = true)) throw forbidden()
val req = call.receive<AccountPasswordChange>()
val hashedPassword = CryptoUtil.hashpw(req.new_password)
+ /**
+ * FIXME: should it check if the password used to authenticate
+ * FIXME: this request _is_ the one being overridden in the database?
+ */
if (!db.customerChangePassword(
accountName,
hashedPassword
))
throw notFound(
- "Account '$accountName' not found",
+ "Account '$accountName' not found (despite it being
authenticated by this call)",
talerEc = TalerErrorCode.TALER_EC_END // FIXME: need at least
GENERIC_NOT_FOUND.
)
call.respond(HttpStatusCode.NoContent)
return@patch
}
+ patch("/accounts/{USERNAME}") {
+ val c = call.authenticateBankRequest(db, TokenScope.readwrite) ?:
throw unauthorized()
+ val accountName = call.getResourceName("USERNAME")
+ // preventing user non-admin X trying on resource Y.
+ if (!accountName.canI(c, withAdmin = true)) throw forbidden()
+ // admin is not allowed itself to change its own details.
+ if (accountName == "admin") throw forbidden("admin account not
patchable")
+ // authentication OK, go on.
+ val req = call.receive<AccountReconfiguration>()
+ /**
+ * This object holds the details of the customer that's affected
+ * by this operation, as it MAY differ from the one being
authenticated.
+ * This typically happens when admin did the request.
+ */
+ val accountCustomer = db.customerGetFromLogin(accountName) ?: throw
notFound(
+ "Account $accountName not found",
+ talerEc = TalerErrorCode.TALER_EC_END // FIXME, define EC.
+ )
+ // Check if a non-admin user tried to change their legal name
+ if (c.login != "admin" && req.name != accountCustomer.name)
+ throw forbidden("non-admin user cannot change their legal name")
+ // Preventing identical data to be overridden.
+ val bankAccount =
db.bankAccountGetFromOwnerId(accountCustomer.expectRowId())
+ ?: throw internalServerError("Customer '${accountCustomer.login}'
lacks bank account.")
+ if (
+ (req.is_exchange == bankAccount.isTalerExchange) &&
+ (req.cashout_address == accountCustomer.cashoutPayto) &&
+ (req.name == c.name) &&
+ (req.challenge_contact_data?.phone == accountCustomer.phone) &&
+ (req.challenge_contact_data?.email == accountCustomer.email)
+ ) {
+ call.respond(HttpStatusCode.NoContent)
+ return@patch
+ }
+ // Not identical, go on writing the DB.
+ throw NotImplementedError("DB part missing.")
+ }
// WITHDRAWAL ENDPOINTS
post("/accounts/{USERNAME}/withdrawals") {
val c = call.authenticateBankRequest(db, TokenScope.readwrite)
@@ -450,14 +489,19 @@ fun Routing.accountsMgmtHandlers(db: Database, ctx:
BankApplicationContext) {
// TRANSACTION ENDPOINT
get("/accounts/{USERNAME}/transactions") {
val c = call.authenticateBankRequest(db, TokenScope.readonly) ?: throw
unauthorized()
- val resourceName = call.expectUriComponent("USERNAME")
- if (c.login != resourceName && c.login != "admin") throw forbidden()
// Collecting params.
- val historyParams = getHistoryParams(call.request) // Making the query.
- val bankAccount = db.bankAccountGetFromOwnerId(c.expectRowId())
- ?: throw internalServerError("Customer '${c.login}' lacks bank
account.")
- val bankAccountId = bankAccount.expectRowId()
+ val resourceName = call.getResourceName("USERNAME")
+ if (!resourceName.canI(c, withAdmin = true)) throw forbidden()
+ val historyParams = getHistoryParams(call.request)
+ val resourceCustomer = db.customerGetFromLogin(resourceName) ?: throw
notFound(
+ hint = "Customer '$resourceName' not found in the database",
+ talerEc = TalerErrorCode.TALER_EC_END // FIXME: need EC.
+ )
+ val bankAccount =
db.bankAccountGetFromOwnerId(resourceCustomer.expectRowId())
+ ?: throw internalServerError("Customer '${resourceCustomer.login}'
lacks bank account.")
val history: List<BankAccountTransaction> =
db.bankTransactionGetHistory(
- start = historyParams.start, delta = historyParams.delta,
bankAccountId = bankAccountId
+ start = historyParams.start,
+ delta = historyParams.delta,
+ bankAccountId = bankAccount.expectRowId()
)
val res = BankAccountTransactionsResponse(transactions =
mutableListOf())
history.forEach {
@@ -526,8 +570,8 @@ fun Routing.accountsMgmtHandlers(db: Database, ctx:
BankApplicationContext) {
}
get("/accounts/{USERNAME}/transactions/{T_ID}") {
val c = call.authenticateBankRequest(db, TokenScope.readonly) ?: throw
unauthorized()
- val accountOwner = call.expectUriComponent("USERNAME") // auth ok,
check rights.
- if (c.login != "admin" && c.login != accountOwner) throw forbidden()
// rights ok, check tx exists.
+ val accountName = call.getResourceName("USERNAME")
+ if (!accountName.canI(c, withAdmin = true)) throw forbidden()
val tId = call.expectUriComponent("T_ID")
val txRowId = try {
tId.toLong()
@@ -535,14 +579,17 @@ fun Routing.accountsMgmtHandlers(db: Database, ctx:
BankApplicationContext) {
logger.error(e.message)
throw badRequest("TRANSACTION_ID is not a number: ${tId}")
}
- val customerRowId = c.dbRowId ?: throw
internalServerError("Authenticated client lacks database entry")
val tx = db.bankTransactionGetFromInternalId(txRowId) ?: throw
notFound(
"Bank transaction '$tId' not found",
TalerErrorCode.TALER_EC_BANK_TRANSACTION_NOT_FOUND
)
- val customerBankAccount = db.bankAccountGetFromOwnerId(customerRowId)
- ?: throw internalServerError("Customer '${c.login}' lacks bank
account.")
- if (tx.bankAccountId != customerBankAccount.bankAccountId) throw
forbidden("Client has no rights over the bank transaction: $tId") // auth and
rights, respond.
+ val accountCustomer = db.customerGetFromLogin(accountName) ?: throw
notFound(
+ hint = "Customer $accountName not found",
+ talerEc = TalerErrorCode.TALER_EC_END // FIXME: need EC.
+ )
+ val customerBankAccount =
db.bankAccountGetFromOwnerId(accountCustomer.expectRowId())
+ ?: throw internalServerError("Customer '${accountCustomer.login}'
lacks bank account.")
+ if (tx.bankAccountId != customerBankAccount.bankAccountId) throw
forbidden("Client has no rights over the bank transaction: $tId")
call.respond(
BankAccountTransactionInfo(
amount = tx.amount,
diff --git a/bank/src/main/kotlin/tech/libeufin/bank/WireGatewayApiHandlers.kt
b/bank/src/main/kotlin/tech/libeufin/bank/WireGatewayApiHandlers.kt
index d9e9b1d4..d4937e79 100644
--- a/bank/src/main/kotlin/tech/libeufin/bank/WireGatewayApiHandlers.kt
+++ b/bank/src/main/kotlin/tech/libeufin/bank/WireGatewayApiHandlers.kt
@@ -43,17 +43,21 @@ fun Routing.talerWireGatewayHandlers(db: Database, ctx:
BankApplicationContext)
get("/accounts/{USERNAME}/taler-wire-gateway/history/incoming") {
val c = call.authenticateBankRequest(db, TokenScope.readonly) ?: throw
unauthorized()
- if (!call.getResourceName("USERNAME").canI(c, withAdmin = true)) throw
forbidden()
+ val accountName = call.getResourceName("USERNAME")
+ if (!accountName.canI(c, withAdmin = true)) throw forbidden()
val params = getHistoryParams(call.request)
- val bankAccount = db.bankAccountGetFromOwnerId(c.expectRowId())
- ?: throw internalServerError("Customer '${c.login}' lacks bank
account.")
+ val accountCustomer = db.customerGetFromLogin(accountName) ?: throw
notFound(
+ hint = "Customer $accountName not found",
+ talerEc = TalerErrorCode.TALER_EC_END // FIXME: need EC.
+ )
+ val bankAccount =
db.bankAccountGetFromOwnerId(accountCustomer.expectRowId())
+ ?: throw internalServerError("Customer '$accountName' lacks bank
account.")
if (!bankAccount.isTalerExchange) throw forbidden("History is not
related to a Taler exchange.")
- val bankAccountId = bankAccount.expectRowId()
val history: List<BankAccountTransaction> =
db.bankTransactionGetHistory(
start = params.start,
delta = params.delta,
- bankAccountId = bankAccountId,
+ bankAccountId = bankAccount.expectRowId(),
withDirection = TransactionDirection.credit
)
if (history.isEmpty()) {
diff --git a/bank/src/main/kotlin/tech/libeufin/bank/helpers.kt
b/bank/src/main/kotlin/tech/libeufin/bank/helpers.kt
index 5329efa1..0efc116b 100644
--- a/bank/src/main/kotlin/tech/libeufin/bank/helpers.kt
+++ b/bank/src/main/kotlin/tech/libeufin/bank/helpers.kt
@@ -164,7 +164,8 @@ fun internalServerError(hint: String?):
LibeufinBankException = LibeufinBankExce
fun notFound(
- hint: String?, talerEc: TalerErrorCode
+ hint: String?,
+ talerEc: TalerErrorCode
): LibeufinBankException = LibeufinBankException(
httpStatus = HttpStatusCode.NotFound, talerError = TalerError(
code = talerEc.code, hint = hint
--
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: Progress with PATCH /accounts/{USERNAME}.,
gnunet <=