commit 525a1b1e2ea9e17c6cf8c1fd927c66eb871b2e47
parent fbf7eb08bf6227e0573f141707a30fa695cba6b6
Author: Antoine A <>
Date: Thu, 19 Oct 2023 08:27:11 +0000
fix error status and code
Diffstat:
5 files changed, 67 insertions(+), 45 deletions(-)
diff --git a/bank/src/main/kotlin/tech/libeufin/bank/CoreBankApi.kt b/bank/src/main/kotlin/tech/libeufin/bank/CoreBankApi.kt
@@ -210,10 +210,10 @@ fun Routing.coreBankAccountsMgmtApi(db: Database, ctx: BankApplicationContext) {
} // auth passed, proceed with activity.
val req = call.receive<RegisterAccountRequest>()
// Prohibit reserved usernames:
- if (reservedAccounts.contains(req.username)) throw conflict(
+ if (reservedAccounts.contains(req.username)) throw forbidden(
"Username '${req.username}' is reserved.",
TalerErrorCode.TALER_EC_BANK_RESERVED_USERNAME_CONFLICT
- ) // TODO conflict or forbidden ?
+ )
// Checking idempotency.
val maybeCustomerExists =
db.customerGetFromLogin(req.username) // Can be null if previous call crashed before completion.
@@ -295,22 +295,19 @@ fun Routing.coreBankAccountsMgmtApi(db: Database, ctx: BankApplicationContext) {
delete("/accounts/{USERNAME}") {
val (login, _) = call.authCheck(db, TokenScope.readwrite, withAdmin = true, requireAdmin = ctx.restrictAccountDeletion)
// Not deleting reserved names.
- if (reservedAccounts.contains(login)) throw conflict(
+ if (reservedAccounts.contains(login)) throw forbidden(
"Cannot delete reserved accounts",
TalerErrorCode.TALER_EC_BANK_RESERVED_USERNAME_CONFLICT
- ) // TODO conflict or forbidden ?
+ )
when (db.customerDeleteIfBalanceIsZero(login)) {
CustomerDeletionResult.CUSTOMER_NOT_FOUND -> throw notFound(
"Customer '$login' not found",
- talerEc = TalerErrorCode.TALER_EC_BANK_UNKNOWN_ACCOUNT
+ TalerErrorCode.TALER_EC_BANK_UNKNOWN_ACCOUNT
)
- CustomerDeletionResult.BALANCE_NOT_ZERO -> throw LibeufinBankException(
- httpStatus = HttpStatusCode.PreconditionFailed, // PreconditionFailed or conflict ?
- talerError = TalerError(
- hint = "Balance is not zero.",
- code = TalerErrorCode.TALER_EC_NONE.code // FIXME: need EC.
- )
+ CustomerDeletionResult.BALANCE_NOT_ZERO -> throw conflict(
+ "Balance is not zero.",
+ TalerErrorCode.TALER_EC_NONE // FIXME: need EC.
)
CustomerDeletionResult.SUCCESS -> call.respond(HttpStatusCode.NoContent)
}
diff --git a/bank/src/main/kotlin/tech/libeufin/bank/Metadata.kt b/bank/src/main/kotlin/tech/libeufin/bank/Metadata.kt
@@ -29,7 +29,7 @@ sealed interface TxMetadata {
// OutgoingTxMetadata
try {
- val (wtid, exchangeBaseUrl) = subject.split(" ", limit=2) ;
+ val (wtid, exchangeBaseUrl) = subject.split(" ", limit=2)
return OutgoingTxMetadata(ShortHashCode(wtid), ExchangeUrl(exchangeBaseUrl))
} catch (e: Exception) { }
diff --git a/bank/src/test/kotlin/CoreBankApiTest.kt b/bank/src/test/kotlin/CoreBankApiTest.kt
@@ -9,6 +9,7 @@ import io.ktor.server.testing.*
import kotlinx.serialization.decodeFromString
import kotlinx.serialization.json.Json
import net.taler.wallet.crypto.Base32Crockford
+import net.taler.common.errorcodes.TalerErrorCode
import org.junit.Test
import org.postgresql.jdbc.PgConnection
import tech.libeufin.bank.*
@@ -59,7 +60,7 @@ class CoreBankAccountsMgmtApiTest {
"password" to "password"
"name" to "John Smith"
})
- }.assertStatus(HttpStatusCode.Conflict)
+ }.assertForbidden().assertErr(TalerErrorCode.TALER_EC_BANK_RESERVED_USERNAME_CONFLICT)
}
}
@@ -90,14 +91,13 @@ class CoreBankAccountsMgmtApiTest {
// Unknown account
client.delete("/accounts/unknown") {
basicAuth("admin", "admin-password")
- }.assertStatus(HttpStatusCode.NotFound)
+ }.assertNotFound().assertErr(TalerErrorCode.TALER_EC_BANK_UNKNOWN_ACCOUNT)
// Reserved account
reservedAccounts.forEach {
client.delete("/accounts/$it") {
basicAuth("admin", "admin-password")
- expectSuccess = false
- }.assertStatus(HttpStatusCode.Conflict)
+ }.assertForbidden().assertErr(TalerErrorCode.TALER_EC_BANK_RESERVED_USERNAME_CONFLICT)
}
// successful deletion
@@ -114,7 +114,7 @@ class CoreBankAccountsMgmtApiTest {
// Trying again must yield 404
client.delete("/accounts/john") {
basicAuth("admin", "admin-password")
- }.assertStatus(HttpStatusCode.NotFound)
+ }.assertNotFound().assertErr(TalerErrorCode.TALER_EC_BANK_UNKNOWN_ACCOUNT)
// fail to delete, due to a non-zero balance.
@@ -126,7 +126,7 @@ class CoreBankAccountsMgmtApiTest {
}.assertOk()
client.delete("/accounts/merchant") {
basicAuth("admin", "admin-password")
- }.assertStatus(HttpStatusCode.PreconditionFailed)
+ }.assertConflict()
client.post("/accounts/merchant/transactions") {
basicAuth("merchant", "merchant-password")
jsonBody(json {
@@ -167,7 +167,7 @@ class CoreBankAccountsMgmtApiTest {
client.patch("/accounts/merchant") {
basicAuth("merchant", "merchant-password")
jsonBody(nameReq)
- }.assertStatus(HttpStatusCode.Forbidden)
+ }.assertForbidden()
// Finally checking that admin does get to patch foo's name.
client.patch("/accounts/merchant") {
basicAuth("admin", "admin-password")
@@ -280,8 +280,8 @@ class CoreBankAccountsMgmtApiTest {
// Check wrong user
client.get("/accounts/exchange") {
- basicAuth("merchanr", "merchanr-password")
- }.assertStatus(HttpStatusCode.Unauthorized)
+ basicAuth("merchant", "merchant-password")
+ }.assertUnauthorized()
}
}
@@ -294,19 +294,19 @@ class CoreBankTransactionsApiTest {
client.request(path) {
this.method = method
basicAuth("unknown", "password")
- }.assertStatus(HttpStatusCode.Unauthorized)
+ }.assertUnauthorized()
// Wrong password
client.request(path) {
this.method = method
basicAuth("merchant", "wrong-password")
- }.assertStatus(HttpStatusCode.Unauthorized)
+ }.assertUnauthorized()
// Wrong account
client.request(path) {
this.method = method
basicAuth("exchange", "merchant-password")
- }.assertStatus(HttpStatusCode.Unauthorized)
+ }.assertUnauthorized()
// TODO check admin rights
}
@@ -451,11 +451,11 @@ class CoreBankTransactionsApiTest {
// Check unknown transaction
client.get("/accounts/merchant/transactions/3") {
basicAuth("merchant", "merchant-password")
- }.assertStatus(HttpStatusCode.NotFound)
+ }.assertNotFound().assertErr(TalerErrorCode.TALER_EC_BANK_TRANSACTION_NOT_FOUND)
// Check wrong transaction
client.get("/accounts/merchant/transactions/2") {
basicAuth("merchant", "merchant-password")
- }.assertStatus(HttpStatusCode.Unauthorized) // Should be NOT_FOUND ?
+ }.assertUnauthorized() // Should be NOT_FOUND ?
}
// POST /transactions
@@ -515,7 +515,7 @@ class CoreBankTransactionsApiTest {
jsonBody(json(valid_req) {
"amount" to "EUR:3.3"
})
- }.assertBadRequest()
+ }.assertBadRequest().assertErr(TalerErrorCode.TALER_EC_GENERIC_CURRENCY_MISMATCH)
// Surpassing the debt limit
client.post("/accounts/merchant/transactions") {
basicAuth("merchant", "merchant-password")
@@ -523,7 +523,7 @@ class CoreBankTransactionsApiTest {
jsonBody(json(valid_req) {
"amount" to "KUDOS:555"
})
- }.assertStatus(HttpStatusCode.Conflict)
+ }.assertConflict().assertErr(TalerErrorCode.TALER_EC_BANK_UNALLOWED_DEBIT)
// Missing message
client.post("/accounts/merchant/transactions") {
basicAuth("merchant", "merchant-password")
@@ -539,7 +539,7 @@ class CoreBankTransactionsApiTest {
jsonBody(json(valid_req) {
"payto_uri" to "payto://iban/UNKNOWN-IBAN-XYZ?message=payout"
})
- }.assertStatus(HttpStatusCode.NotFound)
+ }.assertNotFound().assertErr(TalerErrorCode.TALER_EC_BANK_UNKNOWN_ACCOUNT)
// Transaction to self
client.post("/accounts/merchant/transactions") {
basicAuth("merchant", "merchant-password")
@@ -547,7 +547,7 @@ class CoreBankTransactionsApiTest {
jsonBody(json(valid_req) {
"payto_uri" to "payto://iban/MERCHANT-IBAN-XYZ?message=payout"
})
- }.assertStatus(HttpStatusCode.Conflict)
+ }.assertConflict().assertErr(TalerErrorCode.TALER_EC_BANK_SAME_ACCOUNT)
}
}
diff --git a/bank/src/test/kotlin/WireGatewayApiTest.kt b/bank/src/test/kotlin/WireGatewayApiTest.kt
@@ -9,6 +9,7 @@ import kotlinx.coroutines.*
import org.junit.Test
import tech.libeufin.bank.*
import tech.libeufin.util.CryptoUtil
+import net.taler.common.errorcodes.TalerErrorCode
import java.util.*
import java.time.Instant
import kotlin.test.assertEquals
@@ -54,26 +55,26 @@ class WireGatewayApiTest {
client.request(path) {
this.method = method
basicAuth("unknown", "password")
- }.assertStatus(HttpStatusCode.Unauthorized)
+ }.assertUnauthorized()
// Wrong password
client.request(path) {
this.method = method
basicAuth("merchant", "wrong-password")
- }.assertStatus(HttpStatusCode.Unauthorized)
+ }.assertUnauthorized()
// Wrong account
client.request(path) {
this.method = method
basicAuth("exchange", "merchant-password")
- }.assertStatus(HttpStatusCode.Unauthorized)
+ }.assertUnauthorized()
// Not exchange account
client.request(path) {
this.method = method
if (body != null) jsonBody(body)
basicAuth("merchant", "merchant-password")
- }.assertStatus(HttpStatusCode.Conflict)
+ }.assertConflict().assertErr(TalerErrorCode.TALER_EC_BANK_UNKNOWN_ACCOUNT)
}
// Testing the POST /transfer call from the TWG API.
@@ -93,7 +94,7 @@ class WireGatewayApiTest {
client.post("/accounts/exchange/taler-wire-gateway/transfer") {
basicAuth("exchange", "exchange-password")
jsonBody(valid_req)
- }.assertStatus(HttpStatusCode.Conflict)
+ }.assertConflict().assertErr(TalerErrorCode.TALER_EC_BANK_UNALLOWED_DEBIT)
// Giving debt allowance and checking the OK case.
assert(db.bankAccountSetMaxDebt(
@@ -120,7 +121,7 @@ class WireGatewayApiTest {
"exchange_base_url" to "http://different-exchange.example.com/"
}
)
- }.assertStatus(HttpStatusCode.Conflict)
+ }.assertConflict().assertErr(TalerErrorCode.TALER_EC_BANK_TRANSFER_REQUEST_UID_REUSED)
// Currency mismatch
client.post("/accounts/exchange/taler-wire-gateway/transfer") {
@@ -130,7 +131,7 @@ class WireGatewayApiTest {
"amount" to "EUR:33"
}
)
- }.assertBadRequest()
+ }.assertBadRequest().assertErr(TalerErrorCode.TALER_EC_GENERIC_CURRENCY_MISMATCH)
// Unknown account
client.post("/accounts/exchange/taler-wire-gateway/transfer") {
@@ -142,7 +143,19 @@ class WireGatewayApiTest {
"credit_account" to "payto://iban/UNKNOWN-IBAN-XYZ"
}
)
- }.assertStatus(HttpStatusCode.NotFound)
+ }.assertNotFound().assertErr(TalerErrorCode.TALER_EC_BANK_UNKNOWN_ACCOUNT)
+
+ // Same account
+ client.post("/accounts/exchange/taler-wire-gateway/transfer") {
+ basicAuth("exchange", "exchange-password")
+ jsonBody(
+ json(valid_req) {
+ "request_uid" to randHashCode()
+ "wtid" to randShortHashCode()
+ "credit_account" to "payto://iban/EXCHANGE-IBAN-XYZ"
+ }
+ )
+ }.assertConflict().assertErr(TalerErrorCode.TALER_EC_BANK_SAME_ACCOUNT)
// Bad BASE32 wtid
client.post("/accounts/exchange/taler-wire-gateway/transfer") {
@@ -229,7 +242,7 @@ class WireGatewayApiTest {
// Check error when no transactions
client.get("/accounts/exchange/taler-wire-gateway/history/incoming?delta=7") {
basicAuth("exchange", "exchange-password")
- }.assertStatus(HttpStatusCode.NoContent)
+ }.assertNoContent()
// Gen three transactions using clean add incoming logic
repeat(3) {
@@ -408,7 +421,7 @@ class WireGatewayApiTest {
// Check error when no transactions
client.get("/accounts/exchange/taler-wire-gateway/history/outgoing?delta=7") {
basicAuth("exchange", "exchange-password")
- }.assertStatus(HttpStatusCode.NoContent)
+ }.assertNoContent()
// Gen three transactions using clean transfer logic
repeat(3) {
@@ -499,7 +512,7 @@ class WireGatewayApiTest {
client.post("/accounts/exchange/taler-wire-gateway/admin/add-incoming") {
basicAuth("exchange", "exchange-password")
jsonBody(valid_req)
- }.assertStatus(HttpStatusCode.Conflict)
+ }.assertConflict().assertErr(TalerErrorCode.TALER_EC_BANK_UNALLOWED_DEBIT)
// Giving debt allowance and checking the OK case.
assert(db.bankAccountSetMaxDebt(
@@ -513,10 +526,10 @@ class WireGatewayApiTest {
}.assertOk()
// Trigger conflict due to reused reserve_pub
- client.post("/accounts/exchange/taler-wire-gateway/admin/add-incoming") {
+ client.post("/accounts/exchange/taler-wire-gateway/admin/add-incoming") {
basicAuth("exchange", "exchange-password")
jsonBody(valid_req)
- }.assertStatus(HttpStatusCode.Conflict)
+ }.assertConflict().assertErr(TalerErrorCode.TALER_EC_BANK_DUPLICATE_RESERVE_PUB_SUBJECT)
// Currency mismatch
client.post("/accounts/exchange/taler-wire-gateway/admin/add-incoming") {
@@ -526,7 +539,7 @@ class WireGatewayApiTest {
"amount" to "EUR:33"
}
)
- }.assertBadRequest()
+ }.assertBadRequest().assertErr(TalerErrorCode.TALER_EC_GENERIC_CURRENCY_MISMATCH)
// Unknown account
client.post("/accounts/exchange/taler-wire-gateway/admin/add-incoming") {
@@ -537,7 +550,18 @@ class WireGatewayApiTest {
"debit_account" to "payto://iban/UNKNOWN-IBAN-XYZ"
}
)
- }.assertStatus(HttpStatusCode.NotFound)
+ }.assertNotFound().assertErr(TalerErrorCode.TALER_EC_BANK_UNKNOWN_ACCOUNT)
+
+ // Same account
+ client.post("/accounts/exchange/taler-wire-gateway/admin/add-incoming") {
+ basicAuth("exchange", "exchange-password")
+ jsonBody(
+ json(valid_req) {
+ "reserve_pub" to randEddsaPublicKey()
+ "debit_account" to "payto://iban/EXCHANGE-IBAN-XYZ"
+ }
+ )
+ }.assertConflict().assertErr(TalerErrorCode.TALER_EC_BANK_SAME_ACCOUNT)
// Bad BASE32 reserve_pub
client.post("/accounts/exchange/taler-wire-gateway/admin/add-incoming") {
diff --git a/bank/src/test/kotlin/helpers.kt b/bank/src/test/kotlin/helpers.kt
@@ -110,6 +110,7 @@ fun HttpResponse.assertNotFound(): HttpResponse = assertStatus(HttpStatusCode.No
fun HttpResponse.assertUnauthorized(): HttpResponse = assertStatus(HttpStatusCode.Unauthorized)
fun HttpResponse.assertConflict(): HttpResponse = assertStatus(HttpStatusCode.Conflict)
fun HttpResponse.assertBadRequest(): HttpResponse = assertStatus(HttpStatusCode.BadRequest)
+fun HttpResponse.assertForbidden(): HttpResponse = assertStatus(HttpStatusCode.Forbidden)
suspend fun HttpResponse.assertErr(code: TalerErrorCode): HttpResponse {