summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAntoine A <>2023-10-04 11:20:07 +0000
committerAntoine A <>2023-10-04 11:20:07 +0000
commit377b22e474af8188b5a1e53e68c43f1920b3bcc9 (patch)
tree5381a4afbc59eb5c4543ef559ad4e898ea6a651b
parent05971692600e125018c1450be3558ff11562fbda (diff)
downloadlibeufin-377b22e474af8188b5a1e53e68c43f1920b3bcc9.tar.gz
libeufin-377b22e474af8188b5a1e53e68c43f1920b3bcc9.tar.bz2
libeufin-377b22e474af8188b5a1e53e68c43f1920b3bcc9.zip
Add Crockford32 validation to /taler-wire-gateway/admin/add-incoming
-rw-r--r--bank/src/main/kotlin/tech/libeufin/bank/BankMessages.kt21
-rw-r--r--bank/src/main/kotlin/tech/libeufin/bank/WireGatewayApiHandlers.kt6
-rw-r--r--bank/src/test/kotlin/TalerApiTest.kt37
-rw-r--r--bank/src/test/kotlin/helpers.kt13
4 files changed, 54 insertions, 23 deletions
diff --git a/bank/src/main/kotlin/tech/libeufin/bank/BankMessages.kt b/bank/src/main/kotlin/tech/libeufin/bank/BankMessages.kt
index 035cab5a..f5c4bc5c 100644
--- a/bank/src/main/kotlin/tech/libeufin/bank/BankMessages.kt
+++ b/bank/src/main/kotlin/tech/libeufin/bank/BankMessages.kt
@@ -30,11 +30,11 @@ import java.time.temporal.ChronoUnit
import java.util.*
/**
- * 32-byte hash code.
+ * 32-byte Crockford's Base32 encoded data.
*/
@Serializable()
@JvmInline
-value class ShortHashCode(val encoded: String) {
+value class Base32Crockford32B(val encoded: String) {
init {
val decoded = try {
Base32Crockford.decode(encoded)
@@ -52,11 +52,11 @@ value class ShortHashCode(val encoded: String) {
}
/**
- * 64-byte hash code.
+ * 64-byte Crockford's Base32 encoded data.
*/
@Serializable()
@JvmInline
-value class HashCode(val encoded: String) {
+value class Base32Crockford64B(val encoded: String) {
init {
val decoded = try {
Base32Crockford.decode(encoded)
@@ -73,6 +73,17 @@ value class HashCode(val encoded: String) {
}
}
+/** 32-byte hash code. */
+typealias ShortHashCode = Base32Crockford32B;
+/** 64-byte hash code. */
+typealias HashCode = Base32Crockford64B;
+/**
+ * EdDSA and ECDHE public keys always point on Curve25519
+ * and represented using the standard 256 bits Ed25519 compact format,
+ * converted to Crockford Base32.
+ */
+typealias EddsaPublicKey = Base32Crockford32B;
+
/**
* Allowed lengths for fractional digits in amounts.
*/
@@ -633,7 +644,7 @@ data class BankWithdrawalOperationPostResponse(
@Serializable
data class AddIncomingRequest(
val amount: TalerAmount,
- val reserve_pub: String,
+ val reserve_pub: EddsaPublicKey,
val debit_account: String
)
diff --git a/bank/src/main/kotlin/tech/libeufin/bank/WireGatewayApiHandlers.kt b/bank/src/main/kotlin/tech/libeufin/bank/WireGatewayApiHandlers.kt
index 6da9d70d..cc56c907 100644
--- a/bank/src/main/kotlin/tech/libeufin/bank/WireGatewayApiHandlers.kt
+++ b/bank/src/main/kotlin/tech/libeufin/bank/WireGatewayApiHandlers.kt
@@ -158,7 +158,7 @@ fun Routing.talerWireGatewayHandlers(db: Database, ctx: BankApplicationContext)
"Currency mismatch",
TalerErrorCode.TALER_EC_GENERIC_CURRENCY_MISMATCH
)
- if (db.bankTransactionCheckExists(req.reserve_pub) != null)
+ if (db.bankTransactionCheckExists(req.reserve_pub.encoded) != null)
throw conflict(
"Reserve pub. already used",
TalerErrorCode.TALER_EC_BANK_DUPLICATE_RESERVE_PUB_SUBJECT
@@ -177,7 +177,7 @@ fun Routing.talerWireGatewayHandlers(db: Database, ctx: BankApplicationContext)
amount = req.amount,
creditorAccountId = exchangeAccount.expectRowId(),
transactionDate = txTimestamp,
- subject = req.reserve_pub
+ subject = req.reserve_pub.encoded
)
val res = db.bankTransactionCreate(op)
/**
@@ -189,7 +189,7 @@ fun Routing.talerWireGatewayHandlers(db: Database, ctx: BankApplicationContext)
"Insufficient balance",
TalerErrorCode.TALER_EC_BANK_UNALLOWED_DEBIT
)
- val rowId = db.bankTransactionCheckExists(req.reserve_pub)
+ val rowId = db.bankTransactionCheckExists(req.reserve_pub.encoded)
?: throw internalServerError("Could not find the just inserted bank transaction")
call.respond(
AddIncomingResponse(
diff --git a/bank/src/test/kotlin/TalerApiTest.kt b/bank/src/test/kotlin/TalerApiTest.kt
index 17f6c276..8f4caa32 100644
--- a/bank/src/test/kotlin/TalerApiTest.kt
+++ b/bank/src/test/kotlin/TalerApiTest.kt
@@ -135,7 +135,7 @@ class TalerApiTest {
put("amount", "EUR:33")
}
)
- }.assertStatus(HttpStatusCode.BadRequest)
+ }.assertBadRequest()
// Bad BASE32 wtid
client.post("/accounts/foo/taler-wire-gateway/transfer") {
@@ -145,7 +145,7 @@ class TalerApiTest {
put("wtid", "I love chocolate")
}
)
- }.assertStatus(HttpStatusCode.BadRequest)
+ }.assertBadRequest()
// Bad BASE32 len wtid
client.post("/accounts/foo/taler-wire-gateway/transfer") {
@@ -155,7 +155,7 @@ class TalerApiTest {
put("wtid", randBase32Crockford(31))
}
)
- }.assertStatus(HttpStatusCode.BadRequest)
+ }.assertBadRequest()
// Bad BASE32 request_uid
client.post("/accounts/foo/taler-wire-gateway/transfer") {
@@ -165,7 +165,7 @@ class TalerApiTest {
put("request_uid", "I love chocolate")
}
)
- }.assertStatus(HttpStatusCode.BadRequest)
+ }.assertBadRequest()
// Bad BASE32 len wtid
client.post("/accounts/foo/taler-wire-gateway/transfer") {
@@ -175,7 +175,7 @@ class TalerApiTest {
put("request_uid", randBase32Crockford(65))
}
)
- }.assertStatus(HttpStatusCode.BadRequest)
+ }.assertBadRequest()
}
}
@@ -279,14 +279,31 @@ class TalerApiTest {
application {
corebankWebApp(db, ctx)
}
+ val valid_req = json {
+ put("amount", "KUDOS:44")
+ put("reserve_pub", randEddsaPublicKey())
+ put("debit_account", "${"payto://iban/BAR-IBAN-ABC"}")
+ };
client.post("/accounts/foo/taler-wire-gateway/admin/add-incoming") {
basicAuth("foo", "pw")
- jsonBody(AddIncomingRequest(
- amount = TalerAmount(value = 44, frac = 0, currency = "KUDOS"),
- reserve_pub = "RESERVE-PUB-TEST",
- debit_account = "${"payto://iban/BAR-IBAN-ABC"}"
- ), deflate = true)
+ jsonBody(valid_req, deflate = true)
}.assertOk()
+
+ // Bad BASE32 reserve_pub
+ client.post("/accounts/foo/taler-wire-gateway/admin/add-incoming") {
+ basicAuth("foo", "pw")
+ jsonBody(json(valid_req) {
+ put("reserve_pub", "I love chocolate")
+ })
+ }.assertBadRequest()
+
+ // Bad BASE32 len reserve_pub
+ client.post("/accounts/foo/taler-wire-gateway/admin/add-incoming") {
+ basicAuth("foo", "pw")
+ jsonBody(json(valid_req) {
+ put("reserve_pub", randBase32Crockford(31))
+ })
+ }.assertBadRequest()
}
}
// Selecting withdrawal details from the Integration API endpoint.
diff --git a/bank/src/test/kotlin/helpers.kt b/bank/src/test/kotlin/helpers.kt
index df0669bd..c156ddd4 100644
--- a/bank/src/test/kotlin/helpers.kt
+++ b/bank/src/test/kotlin/helpers.kt
@@ -16,8 +16,8 @@ fun HttpResponse.assertStatus(status: HttpStatusCode): HttpResponse {
assertEquals(status, this.status);
return this
}
-
fun HttpResponse.assertOk(): HttpResponse = assertStatus(HttpStatusCode.OK)
+fun HttpResponse.assertBadRequest(): HttpResponse = assertStatus(HttpStatusCode.BadRequest)
fun BankTransactionResult.assertSuccess() {
@@ -39,14 +39,13 @@ inline fun <reified B> HttpRequestBuilder.jsonBody(b: B, deflate: Boolean = fals
/* ----- Json DSL ----- */
-inline fun json(from: JsonObject = JsonObject(emptyMap()), builderAction: JsonBuilder2.() -> Unit): JsonObject {
- val builder = JsonBuilder2(from)
+inline fun json(from: JsonObject = JsonObject(emptyMap()), builderAction: JsonBuilder.() -> Unit): JsonObject {
+ val builder = JsonBuilder(from)
builder.apply(builderAction)
- println(builder.content)
return JsonObject(builder.content)
}
-class JsonBuilder2(from: JsonObject) {
+class JsonBuilder(from: JsonObject) {
val content: MutableMap<String, JsonElement> = from.toMutableMap()
inline fun <reified B> put(name: String, b: B) {
@@ -69,4 +68,8 @@ fun randHashCode(): HashCode {
fun randShortHashCode(): ShortHashCode {
return ShortHashCode(randBase32Crockford(32))
+}
+
+fun randEddsaPublicKey(): EddsaPublicKey {
+ return EddsaPublicKey(randBase32Crockford(32))
} \ No newline at end of file