commit 2e04e5e970163f1920c486197ce0fadc7f04c481
parent 9c36aa1839fd0279d5b045b28ae9313bfbf81c39
Author: Florian Dold <florian.dold@gmail.com>
Date: Wed, 20 May 2020 18:01:39 +0530
error reporting / receiveJson
Diffstat:
2 files changed, 34 insertions(+), 10 deletions(-)
diff --git a/nexus/src/main/kotlin/tech/libeufin/nexus/JSON.kt b/nexus/src/main/kotlin/tech/libeufin/nexus/JSON.kt
@@ -1,5 +1,6 @@
package tech.libeufin.nexus
+import com.fasterxml.jackson.annotation.JsonAutoDetect
import org.joda.time.DateTime
import tech.libeufin.util.*
import java.time.LocalDate
@@ -164,6 +165,10 @@ data class CollectedTransaction(
val end: String?
)
+data class BankProtocolsResponse(
+ val protocols: List<String>
+)
+
/** Request type of "POST /prepared-payments" */
data class PreparedPaymentRequest(
val iban: String,
diff --git a/nexus/src/main/kotlin/tech/libeufin/nexus/Main.kt b/nexus/src/main/kotlin/tech/libeufin/nexus/Main.kt
@@ -23,6 +23,9 @@ import com.fasterxml.jackson.core.util.DefaultIndenter
import com.fasterxml.jackson.core.util.DefaultPrettyPrinter
import com.fasterxml.jackson.databind.JsonNode
import com.fasterxml.jackson.databind.SerializationFeature
+import com.fasterxml.jackson.databind.exc.MismatchedInputException
+import com.fasterxml.jackson.module.kotlin.KotlinModule
+import com.fasterxml.jackson.module.kotlin.MissingKotlinParameterException
import com.fasterxml.jackson.module.kotlin.jacksonObjectMapper
import com.github.ajalt.clikt.core.CliktCommand
import com.github.ajalt.clikt.core.ProgramResult
@@ -30,11 +33,14 @@ import com.github.ajalt.clikt.core.subcommands
import com.github.ajalt.clikt.parameters.arguments.argument
import com.github.ajalt.clikt.parameters.options.option
import com.github.ajalt.clikt.parameters.options.prompt
+import io.ktor.application.ApplicationCall
import io.ktor.application.ApplicationCallPipeline
import io.ktor.application.call
import io.ktor.application.install
import io.ktor.client.HttpClient
-import io.ktor.features.*
+import io.ktor.features.CallLogging
+import io.ktor.features.ContentNegotiation
+import io.ktor.features.StatusPages
import io.ktor.http.ContentType
import io.ktor.http.HttpStatusCode
import io.ktor.jackson.jackson
@@ -63,12 +69,12 @@ import org.slf4j.event.Level
import tech.libeufin.util.*
import tech.libeufin.util.CryptoUtil.hashpw
import tech.libeufin.util.ebics_h004.HTDResponseOrderData
-import java.text.DateFormat
import java.util.zip.InflaterInputStream
import javax.crypto.EncryptedPrivateKeyInfo
import javax.sql.rowset.serial.SerialBlob
data class NexusError(val statusCode: HttpStatusCode, val reason: String) : Exception()
+
val logger: Logger = LoggerFactory.getLogger("tech.libeufin.nexus")
suspend fun handleEbicsSendMSG(
@@ -167,17 +173,17 @@ suspend fun handleEbicsSendMSG(
return response
}
-class NexusCommand: CliktCommand() {
+class NexusCommand : CliktCommand() {
override fun run() = Unit
}
-class Serve: CliktCommand("Run nexus HTTP server") {
+class Serve : CliktCommand("Run nexus HTTP server") {
override fun run() {
serverMain()
}
}
-class Superuser: CliktCommand("Add superuser or change pw") {
+class Superuser : CliktCommand("Add superuser or change pw") {
private val username by argument()
private val password by option().prompt(requireConfirmation = true, hideInput = true)
override fun run() {
@@ -207,6 +213,16 @@ fun main(args: Array<String>) {
.main(args)
}
+suspend inline fun <reified T : Any>ApplicationCall.receiveJson(): T {
+ try {
+ return this.receive<T>();
+ } catch (e: MissingKotlinParameterException) {
+ throw NexusError(HttpStatusCode.BadRequest, "Missing value for ${e.pathReference}")
+ } catch (e: MismatchedInputException) {
+ throw NexusError(HttpStatusCode.BadRequest, "Invalid value for ${e.pathReference}")
+ }
+}
+
@ExperimentalIoApi
@KtorExperimentalAPI
fun serverMain() {
@@ -227,6 +243,7 @@ fun serverMain() {
indentArraysWith(DefaultPrettyPrinter.FixedSpaceIndenter.instance)
indentObjectsWith(DefaultIndenter(" ", "\n"))
})
+ registerModule(KotlinModule(nullisSameAsDefault = true))
//registerModule(JavaTimeModule())
}
}
@@ -307,7 +324,7 @@ fun serverMain() {
* Add a new ordinary user in the system (requires superuser privileges)
*/
post("/users") {
- val body = call.receive<User>()
+ val body = call.receiveJson<User>()
transaction {
val currentUser = authenticateRequest(call.request.headers["Authorization"])
if (!currentUser.superuser) {
@@ -325,7 +342,8 @@ fun serverMain() {
)
return@post
}
- get("/bank-connection-protocols") {
+ get("/bank-connection-protocols") {
+ call.respond(HttpStatusCode.OK, BankProtocolsResponse(listOf("ebics", "loopback")))
return@get
}
/**
@@ -528,7 +546,7 @@ fun serverMain() {
when (transport.type) {
"ebics" -> {
if (body.get("backup") != null) {
- val backup = jacksonObjectMapper().treeToValue(body,EbicsKeysBackupJson::class.java)
+ val backup = jacksonObjectMapper().treeToValue(body, EbicsKeysBackupJson::class.java)
val (authKey, encKey, sigKey) = try {
Triple(
CryptoUtil.decryptKey(
@@ -578,7 +596,8 @@ fun serverMain() {
return@post
}
if (body.get("data") != null) {
- val data = jacksonObjectMapper().treeToValue((body.get("data")), EbicsNewTransport::class.java)
+ val data =
+ jacksonObjectMapper().treeToValue((body.get("data")), EbicsNewTransport::class.java)
val pairA = CryptoUtil.generateRsaKeyPair(2048)
val pairB = CryptoUtil.generateRsaKeyPair(2048)
val pairC = CryptoUtil.generateRsaKeyPair(2048)
@@ -651,7 +670,7 @@ fun serverMain() {
transportId = body.name,
msg = ensureNonNull(call.parameters["MSG"]),
sync = true
- )
+ )
call.respondText(response)
}
else -> throw NexusError(