commit 7d33776d78129e3f4f3bbcfbcff0843fb4972bae
parent 51ec1715b78c510cd455dc13243b81e28f67c0ff
Author: Florian Dold <florian.dold@gmail.com>
Date: Mon, 30 Sep 2019 10:01:04 +0200
make running the sandbox from the cmdline easier
Diffstat:
8 files changed, 230 insertions(+), 230 deletions(-)
diff --git a/.idea/gradle.xml b/.idea/gradle.xml
@@ -13,6 +13,7 @@
<option value="$PROJECT_DIR$" />
</set>
</option>
+ <option name="useAutoImport" value="true" />
<option name="useQualifiedModuleNames" value="true" />
</GradleProjectSettings>
</option>
diff --git a/.idea/misc.xml b/.idea/misc.xml
@@ -1,4 +1,5 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="ExternalStorageConfigurationManager" enabled="true" />
+ <component name="ProjectRootManager" version="2" project-jdk-name="12" project-jdk-type="JavaSDK" />
</project>
\ No newline at end of file
diff --git a/README b/README
@@ -1,5 +1,5 @@
-Description.
-============
+Description
+===========
The Libeufin Sandbox aims at implementing the server side of multiple
banking protocols currently used in the European Union. Notably, the
@@ -7,25 +7,15 @@ EBICS, FinTS, and the major protocols that banks will employ to respect
the PSD2 regulation: https://ec.europa.eu/info/law/payment-services-psd-2-directive-eu-2015-2366_en
-Building and running the sandbox.
-=================================
+Running the sandbox
+===================
-The sandox must be exported as JAR in order to be run.
-The following command exports the JAR in GNU/Linux systems.
+Run the sandbox with the following command
$ cd <this repository>
-$ ./gradlew jar
+$ ./gradlew run --console=plain
-If the previous step worked, then a new JAR file should
-be located under <this repository>/build/libs/sandbox-$VERSION.jar,
-where $VERSION reflects the value of the 'version' global
-variable from <this repository>/build.gradle.
+Documentation
+=============
-The following command runs the sandbox:
-
-$ java -jar <this repository>/build/libs/sandbox-$VERSION.jar
-
-MS Windows users.
-=================
-The steps to follow are the same as in GNU/Linux systems, except
-that the command "gradlew.bat jar" would produce the JAR file.
+See https://docs.libeufin.tech/ for the documentation.
diff --git a/build.gradle b/build.gradle
@@ -1,6 +1,7 @@
plugins {
id 'java'
- id 'org.jetbrains.kotlin.jvm' version '1.3.41'
+ id 'application'
+ id 'org.jetbrains.kotlin.jvm' version '1.3.50'
}
version '1.0-SNAPSHOT'
@@ -28,14 +29,21 @@ dependencies {
}
compileKotlin {
- kotlinOptions.jvmTarget = "1.8"
+ kotlinOptions {
+ jvmTarget = "1.8"
+ }
}
compileTestKotlin {
- kotlinOptions.jvmTarget = "1.8"
+ kotlinOptions {
+ jvmTarget = "1.8"
+ }
}
-jar {
+application {
+ mainClassName = "tech.libeufin.MainKt"
+}
+jar {
manifest {
attributes "Main-Class": "tech.libeufin.MainKt"
diff --git a/gradle/wrapper/gradle-wrapper.properties b/gradle/wrapper/gradle-wrapper.properties
@@ -1,5 +1,6 @@
+#Mon Sep 30 09:20:29 CEST 2019
+distributionUrl=https\://services.gradle.org/distributions/gradle-5.2.1-all.zip
distributionBase=GRADLE_USER_HOME
distributionPath=wrapper/dists
-distributionUrl=https\://services.gradle.org/distributions/gradle-5.2.1-bin.zip
-zipStoreBase=GRADLE_USER_HOME
zipStorePath=wrapper/dists
+zipStoreBase=GRADLE_USER_HOME
diff --git a/src/main/kotlin/Main.kt b/src/main/kotlin/Main.kt
@@ -1,203 +0,0 @@
-/*
- * This file is part of LibEuFin.
- * Copyright (C) 2019 Stanisci and Dold.
-
- * LibEuFin is free software; you can redistribute it and/or modify
- * it under the terms of the GNU Affero General Public License as
- * published by the Free Software Foundation; either version 3, or
- * (at your option) any later version.
-
- * LibEuFin is distributed in the hope that it will be useful, but
- * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
- * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General
- * Public License for more details.
-
- * You should have received a copy of the GNU Affero General Public
- * License along with LibEuFin; see the file COPYING. If not, see
- * <http://www.gnu.org/licenses/>
- */
-
-package tech.libeufin
-
-import io.ktor.application.call
-import io.ktor.application.install
-import io.ktor.features.CallLogging
-import io.ktor.features.ContentNegotiation
-import io.ktor.gson.gson
-import io.ktor.http.ContentType
-import io.ktor.http.HttpStatusCode
-import io.ktor.request.receive
-import io.ktor.request.receiveText
-import io.ktor.response.respond
-import io.ktor.response.respondText
-import io.ktor.routing.get
-import io.ktor.routing.post
-import io.ktor.routing.routing
-import io.ktor.server.engine.embeddedServer
-import io.ktor.server.netty.Netty
-import org.jetbrains.exposed.sql.transactions.transaction
-import org.w3c.dom.Document
-import tech.libeufin.messages.HEVResponseDataType
-import tech.libeufin.tech.libeufin.*
-import java.text.DateFormat
-import javax.xml.bind.JAXBElement
-
-fun main() {
-
- val xmlProcess = XMLTransform()
- val logger = getLogger()
- dbCreateTables()
-
- val server = embeddedServer(Netty, port = 5000) {
-
- install(CallLogging)
- install(ContentNegotiation) {
- gson {
- setDateFormat(DateFormat.LONG)
- setPrettyPrinting()
- }
- }
- routing {
- get("/") {
- logger.debug("GET: not implemented")
- call.respondText("Hello LibEuFin!", ContentType.Text.Plain)
- return@get
- }
-
- post("/admin/customers") {
- val body = try {
- call.receive<CustomerRequest>()
- } catch (e: Exception) {
- e.printStackTrace()
- call.respond(
- HttpStatusCode.BadRequest,
- SandboxError(e.message.toString())
- )
- return@post
- }
- logger.info(body.toString())
-
- val returnId = transaction {
- val myUserId = EbicsUser.new { }
- val myPartnerId = EbicsPartner.new { }
- val mySystemId = EbicsSystem.new { }
- val subscriber = EbicsSubscriber.new {
- userId = myUserId
- partnerId = myPartnerId
- systemId = mySystemId
- state = SubscriberStates.NEW
- }
- println("subscriber ID: ${subscriber.id.value}")
- val customer = BankCustomer.new {
- name = body.name
- ebicsSubscriber = subscriber
- }
- println("name: ${customer.name}")
- return@transaction customer.id.value
- }
-
- call.respond(
- HttpStatusCode.OK,
- CustomerResponse(id = returnId)
- )
-
- return@post
- }
-
- get("/admin/customers/{id}") {
-
- val id: Int = try {
- call.parameters["id"]!!.toInt()
- } catch (e: NumberFormatException) {
- call.respond(
- HttpStatusCode.BadRequest,
- SandboxError(e.message.toString())
- )
- return@get
- }
-
- logger.info("Querying ID: $id")
-
- val customerInfo = transaction {
- val customer = BankCustomer.findById(id) ?: return@transaction null
- CustomerInfo(
- customer.name,
- customerEbicsInfo = CustomerEbicsInfo(
- customer.ebicsSubscriber.userId.id.value
- )
- )
- }
-
- if (null == customerInfo) {
- call.respond(
- HttpStatusCode.NotFound,
- SandboxError("id $id not found")
- )
- return@get
- }
-
- call.respond(HttpStatusCode.OK, customerInfo)
- }
-
- post("/ebicsweb") {
- val body: String = call.receiveText()
- logger.debug("Body: $body")
-
- val isValid = xmlProcess.validateFromString(body)
-
- if (!isValid) {
- logger.error("Invalid request received")
- call.respondText(
- contentType = ContentType.Application.Xml,
- status = HttpStatusCode.BadRequest
- ) { "Bad request" }
- return@post
- }
-
- val bodyDocument: Document? = xmlProcess.parseStringIntoDom(body)
- if (null == bodyDocument) {
- /* Should never happen. */
- logger.error("A valid document failed to parse into DOM!")
- call.respondText(
- contentType = ContentType.Application.Xml,
- status = HttpStatusCode.InternalServerError
- ) { "Internal server error" }
- return@post
- }
- logger.info(bodyDocument.documentElement.localName)
-
- when (bodyDocument.documentElement.localName) {
- "ebicsHEVRequest" -> {
- val hevResponse = HEVResponse(
- "000000",
- "EBICS_OK",
- arrayOf(
- ProtocolAndVersion("H003", "02.40"),
- ProtocolAndVersion("H004", "02.50")
- )
- )
-
- val jaxbHEV: JAXBElement<HEVResponseDataType> = hevResponse.makeHEVResponse()
- val responseText: String? = xmlProcess.getStringFromJaxb(jaxbHEV)
- // FIXME: check if String is actually non-NULL!
- call.respondText(
- contentType = ContentType.Application.Xml,
- status = HttpStatusCode.OK
- ) { responseText.toString() }
- return@post
- }
- else -> {
- /* Log to console and return "unknown type" */
- logger.info("Unknown message, just logging it!")
- call.respondText(
- contentType = ContentType.Application.Xml,
- status = HttpStatusCode.NotFound
- ) { "Not found" }
- return@post
- }
- }
- }
- }
- }
- server.start(wait = true)
-}
-\ No newline at end of file
diff --git a/src/main/kotlin/tech/libeufin/DB.kt b/src/main/kotlin/tech/libeufin/DB.kt
@@ -1,4 +1,4 @@
-package tech.libeufin.tech.libeufin
+package tech.libeufin
import org.jetbrains.exposed.dao.*
import org.jetbrains.exposed.sql.*
diff --git a/src/main/kotlin/tech/libeufin/Main.kt b/src/main/kotlin/tech/libeufin/Main.kt
@@ -0,0 +1,202 @@
+/*
+ * This file is part of LibEuFin.
+ * Copyright (C) 2019 Stanisci and Dold.
+
+ * LibEuFin is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as
+ * published by the Free Software Foundation; either version 3, or
+ * (at your option) any later version.
+
+ * LibEuFin is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+ * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General
+ * Public License for more details.
+
+ * You should have received a copy of the GNU Affero General Public
+ * License along with LibEuFin; see the file COPYING. If not, see
+ * <http://www.gnu.org/licenses/>
+ */
+
+package tech.libeufin
+
+import io.ktor.application.call
+import io.ktor.application.install
+import io.ktor.features.CallLogging
+import io.ktor.features.ContentNegotiation
+import io.ktor.gson.gson
+import io.ktor.http.ContentType
+import io.ktor.http.HttpStatusCode
+import io.ktor.request.receive
+import io.ktor.request.receiveText
+import io.ktor.response.respond
+import io.ktor.response.respondText
+import io.ktor.routing.get
+import io.ktor.routing.post
+import io.ktor.routing.routing
+import io.ktor.server.engine.embeddedServer
+import io.ktor.server.netty.Netty
+import org.jetbrains.exposed.sql.transactions.transaction
+import org.w3c.dom.Document
+import tech.libeufin.messages.HEVResponseDataType
+import java.text.DateFormat
+import javax.xml.bind.JAXBElement
+
+fun main() {
+
+ val xmlProcess = XMLTransform()
+ val logger = getLogger()
+ dbCreateTables()
+
+ val server = embeddedServer(Netty, port = 5000) {
+
+ install(CallLogging)
+ install(ContentNegotiation) {
+ gson {
+ setDateFormat(DateFormat.LONG)
+ setPrettyPrinting()
+ }
+ }
+ routing {
+ get("/") {
+ logger.debug("GET: not implemented")
+ call.respondText("Hello LibEuFin!", ContentType.Text.Plain)
+ return@get
+ }
+
+ post("/admin/customers") {
+ val body = try {
+ call.receive<CustomerRequest>()
+ } catch (e: Exception) {
+ e.printStackTrace()
+ call.respond(
+ HttpStatusCode.BadRequest,
+ SandboxError(e.message.toString())
+ )
+ return@post
+ }
+ logger.info(body.toString())
+
+ val returnId = transaction {
+ val myUserId = EbicsUser.new { }
+ val myPartnerId = EbicsPartner.new { }
+ val mySystemId = EbicsSystem.new { }
+ val subscriber = EbicsSubscriber.new {
+ userId = myUserId
+ partnerId = myPartnerId
+ systemId = mySystemId
+ state = SubscriberStates.NEW
+ }
+ println("subscriber ID: ${subscriber.id.value}")
+ val customer = BankCustomer.new {
+ name = body.name
+ ebicsSubscriber = subscriber
+ }
+ println("name: ${customer.name}")
+ return@transaction customer.id.value
+ }
+
+ call.respond(
+ HttpStatusCode.OK,
+ CustomerResponse(id = returnId)
+ )
+
+ return@post
+ }
+
+ get("/admin/customers/{id}") {
+
+ val id: Int = try {
+ call.parameters["id"]!!.toInt()
+ } catch (e: NumberFormatException) {
+ call.respond(
+ HttpStatusCode.BadRequest,
+ SandboxError(e.message.toString())
+ )
+ return@get
+ }
+
+ logger.info("Querying ID: $id")
+
+ val customerInfo = transaction {
+ val customer = BankCustomer.findById(id) ?: return@transaction null
+ CustomerInfo(
+ customer.name,
+ customerEbicsInfo = CustomerEbicsInfo(
+ customer.ebicsSubscriber.userId.id.value
+ )
+ )
+ }
+
+ if (null == customerInfo) {
+ call.respond(
+ HttpStatusCode.NotFound,
+ SandboxError("id $id not found")
+ )
+ return@get
+ }
+
+ call.respond(HttpStatusCode.OK, customerInfo)
+ }
+
+ post("/ebicsweb") {
+ val body: String = call.receiveText()
+ logger.debug("Body: $body")
+
+ val isValid = xmlProcess.validateFromString(body)
+
+ if (!isValid) {
+ logger.error("Invalid request received")
+ call.respondText(
+ contentType = ContentType.Application.Xml,
+ status = HttpStatusCode.BadRequest
+ ) { "Bad request" }
+ return@post
+ }
+
+ val bodyDocument: Document? = xmlProcess.parseStringIntoDom(body)
+ if (null == bodyDocument) {
+ /* Should never happen. */
+ logger.error("A valid document failed to parse into DOM!")
+ call.respondText(
+ contentType = ContentType.Application.Xml,
+ status = HttpStatusCode.InternalServerError
+ ) { "Internal server error" }
+ return@post
+ }
+ logger.info(bodyDocument.documentElement.localName)
+
+ when (bodyDocument.documentElement.localName) {
+ "ebicsHEVRequest" -> {
+ val hevResponse = HEVResponse(
+ "000000",
+ "EBICS_OK",
+ arrayOf(
+ ProtocolAndVersion("H003", "02.40"),
+ ProtocolAndVersion("H004", "02.50")
+ )
+ )
+
+ val jaxbHEV: JAXBElement<HEVResponseDataType> = hevResponse.makeHEVResponse()
+ val responseText: String? = xmlProcess.getStringFromJaxb(jaxbHEV)
+ // FIXME: check if String is actually non-NULL!
+ call.respondText(
+ contentType = ContentType.Application.Xml,
+ status = HttpStatusCode.OK
+ ) { responseText.toString() }
+ return@post
+ }
+ else -> {
+ /* Log to console and return "unknown type" */
+ logger.info("Unknown message, just logging it!")
+ call.respondText(
+ contentType = ContentType.Application.Xml,
+ status = HttpStatusCode.NotFound
+ ) { "Not found" }
+ return@post
+ }
+ }
+ }
+ }
+ }
+ server.start(wait = true)
+}
+\ No newline at end of file