[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]
[libeufin] branch master updated (62d0490 -> 786b70a)
From: |
gnunet |
Subject: |
[libeufin] branch master updated (62d0490 -> 786b70a) |
Date: |
Tue, 29 Jun 2021 15:59:11 +0200 |
This is an automated email from the git hooks/post-receive script.
ms pushed a change to branch master
in repository libeufin.
from 62d0490 Importing dependencies to implement form-based authentication.
new db3e710 DB: making Ebics subscriber point at bank accounts.
new cf83585 Commenting out Jinja initialization.
new 1117d23 Jinja and form-auth experiments
new 1ec8f2c drafting user creation
new c9a3b09 drafting bank config table
new 5b88146 CLI command to configure the Sandbox
new 786b70a helper that returns a bank configuration, given the hostname.
The 7 revisions listed above as "new" are entirely new to this
repository and will be described in separate emails. The revisions
listed as "add" were already present in the repository and have only
been added to this reference.
Summary of changes:
.idea/libraries-with-intellij-classes.xml | 65 ++++++++++++
.../src/main/kotlin/tech/libeufin/sandbox/DB.kt | 49 ++++++++-
.../main/kotlin/tech/libeufin/sandbox/Helpers.kt | 92 +++++++++++++++-
.../src/main/kotlin/tech/libeufin/sandbox/Main.kt | 117 +++++++++++++++++++--
4 files changed, 308 insertions(+), 15 deletions(-)
create mode 100644 .idea/libraries-with-intellij-classes.xml
diff --git a/.idea/libraries-with-intellij-classes.xml
b/.idea/libraries-with-intellij-classes.xml
new file mode 100644
index 0000000..9fa3156
--- /dev/null
+++ b/.idea/libraries-with-intellij-classes.xml
@@ -0,0 +1,65 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<project version="4">
+ <component name="libraries-with-intellij-classes">
+ <option name="intellijApiContainingLibraries">
+ <list>
+ <LibraryCoordinatesState>
+ <option name="artifactId" value="ideaIU" />
+ <option name="groupId" value="com.jetbrains.intellij.idea" />
+ </LibraryCoordinatesState>
+ <LibraryCoordinatesState>
+ <option name="artifactId" value="ideaIU" />
+ <option name="groupId" value="com.jetbrains" />
+ </LibraryCoordinatesState>
+ <LibraryCoordinatesState>
+ <option name="artifactId" value="ideaIC" />
+ <option name="groupId" value="com.jetbrains.intellij.idea" />
+ </LibraryCoordinatesState>
+ <LibraryCoordinatesState>
+ <option name="artifactId" value="ideaIC" />
+ <option name="groupId" value="com.jetbrains" />
+ </LibraryCoordinatesState>
+ <LibraryCoordinatesState>
+ <option name="artifactId" value="pycharmPY" />
+ <option name="groupId" value="com.jetbrains.intellij.pycharm" />
+ </LibraryCoordinatesState>
+ <LibraryCoordinatesState>
+ <option name="artifactId" value="pycharmPY" />
+ <option name="groupId" value="com.jetbrains" />
+ </LibraryCoordinatesState>
+ <LibraryCoordinatesState>
+ <option name="artifactId" value="pycharmPC" />
+ <option name="groupId" value="com.jetbrains.intellij.pycharm" />
+ </LibraryCoordinatesState>
+ <LibraryCoordinatesState>
+ <option name="artifactId" value="pycharmPC" />
+ <option name="groupId" value="com.jetbrains" />
+ </LibraryCoordinatesState>
+ <LibraryCoordinatesState>
+ <option name="artifactId" value="clion" />
+ <option name="groupId" value="com.jetbrains.intellij.clion" />
+ </LibraryCoordinatesState>
+ <LibraryCoordinatesState>
+ <option name="artifactId" value="clion" />
+ <option name="groupId" value="com.jetbrains" />
+ </LibraryCoordinatesState>
+ <LibraryCoordinatesState>
+ <option name="artifactId" value="riderRD" />
+ <option name="groupId" value="com.jetbrains.intellij.rider" />
+ </LibraryCoordinatesState>
+ <LibraryCoordinatesState>
+ <option name="artifactId" value="riderRD" />
+ <option name="groupId" value="com.jetbrains" />
+ </LibraryCoordinatesState>
+ <LibraryCoordinatesState>
+ <option name="artifactId" value="goland" />
+ <option name="groupId" value="com.jetbrains.intellij.goland" />
+ </LibraryCoordinatesState>
+ <LibraryCoordinatesState>
+ <option name="artifactId" value="goland" />
+ <option name="groupId" value="com.jetbrains" />
+ </LibraryCoordinatesState>
+ </list>
+ </option>
+ </component>
+</project>
\ No newline at end of file
diff --git a/sandbox/src/main/kotlin/tech/libeufin/sandbox/DB.kt
b/sandbox/src/main/kotlin/tech/libeufin/sandbox/DB.kt
index 1cc38fd..99bed21 100644
--- a/sandbox/src/main/kotlin/tech/libeufin/sandbox/DB.kt
+++ b/sandbox/src/main/kotlin/tech/libeufin/sandbox/DB.kt
@@ -22,10 +22,13 @@ package tech.libeufin.sandbox
import org.jetbrains.exposed.dao.Entity
import org.jetbrains.exposed.dao.EntityClass
import org.jetbrains.exposed.dao.IntEntity
+import org.jetbrains.exposed.dao.LongEntity
import org.jetbrains.exposed.dao.IntEntityClass
+import org.jetbrains.exposed.dao.LongEntityClass
import org.jetbrains.exposed.dao.id.EntityID
import org.jetbrains.exposed.dao.id.IdTable
import org.jetbrains.exposed.dao.id.IntIdTable
+import org.jetbrains.exposed.dao.id.LongIdTable
import org.jetbrains.exposed.sql.*
import org.jetbrains.exposed.sql.transactions.TransactionManager
import org.jetbrains.exposed.sql.transactions.transaction
@@ -84,6 +87,39 @@ enum class KeyState {
RELEASED
}
+object SandboxConfigsTable : LongIdTable() {
+ val currency = text("currency")
+ val allowRegistrations = bool("allowRegistrations")
+ val bankDebtLimit = integer("bankDebtLimit")
+ val usersDebtLimit = integer("usersDebtLimit")
+ val hostname = text("hostname")
+}
+
+class SandboxConfigEntity(id: EntityID<Long>) : LongEntity(id) {
+ companion object :
LongEntityClass<SandboxConfigEntity>(SandboxConfigsTable)
+ var currency by SandboxConfigsTable.currency
+ var allowRegistrations by SandboxConfigsTable.allowRegistrations
+ var bankDebtLimit by SandboxConfigsTable.bankDebtLimit
+ var usersDebtLimit by SandboxConfigsTable.usersDebtLimit
+ var name by SandboxConfigsTable.hostname
+}
+
+object SandboxUsersTable : LongIdTable() {
+ val username = text("username")
+ val passwordHash = text("password")
+ val superuser = bool("superuser") // admin
+ val bankAccount = reference("bankAccout", BankAccountsTable)
+}
+
+class SandboxUserEntity(id: EntityID<Long>) : LongEntity(id) {
+ companion object : LongEntityClass<SandboxUserEntity>(SandboxUsersTable)
+ var username by SandboxUsersTable.username
+ var passwordHash by SandboxUsersTable.passwordHash
+ var superuser by SandboxUsersTable.superuser
+ var bankAccount by BankAccountEntity referencedOn
SandboxUsersTable.bankAccount
+}
+
+
/**
* This table stores RSA public keys of subscribers.
*/
@@ -94,7 +130,6 @@ object EbicsSubscriberPublicKeysTable : IntIdTable() {
class EbicsSubscriberPublicKeyEntity(id: EntityID<Int>) : IntEntity(id) {
companion object :
IntEntityClass<EbicsSubscriberPublicKeyEntity>(EbicsSubscriberPublicKeysTable)
-
var rsaPublicKey by EbicsSubscriberPublicKeysTable.rsaPublicKey
var state by EbicsSubscriberPublicKeysTable.state
}
@@ -133,6 +168,9 @@ object EbicsSubscribersTable : IntIdTable() {
val authenticationKey = reference("authorizationKey",
EbicsSubscriberPublicKeysTable).nullable()
val nextOrderID = integer("nextOrderID")
val state = enumeration("state", SubscriberState::class)
+ // setting as nullable to integrate this change more seamlessly into the
current
+ // implementation. Can be removed eventually.
+ val bankAccount = reference("bankAccount", BankAccountsTable).nullable()
}
class EbicsSubscriberEntity(id: EntityID<Int>) : IntEntity(id) {
@@ -147,6 +185,7 @@ class EbicsSubscriberEntity(id: EntityID<Int>) :
IntEntity(id) {
var authenticationKey by EbicsSubscriberPublicKeyEntity
optionalReferencedOn EbicsSubscribersTable.authenticationKey
var nextOrderID by EbicsSubscribersTable.nextOrderID
var state by EbicsSubscribersTable.state
+ var bankAccount by BankAccountEntity optionalReferencedOn
EbicsSubscribersTable.bankAccount
}
/**
@@ -285,7 +324,6 @@ object BankAccountsTable : IntIdTable() {
val bic = text("bic")
val name = text("name")
val label = text("label").uniqueIndex("accountLabelIndex")
- val subscriber = reference("subscriber", EbicsSubscribersTable)
val currency = text("currency")
}
@@ -296,7 +334,6 @@ class BankAccountEntity(id: EntityID<Int>) : IntEntity(id) {
var bic by BankAccountsTable.bic
var name by BankAccountsTable.name
var label by BankAccountsTable.label
- var subscriber by EbicsSubscriberEntity referencedOn
BankAccountsTable.subscriber
var currency by BankAccountsTable.currency
}
@@ -327,7 +364,9 @@ fun dbDropTables(dbConnectionString: String) {
BankAccountTransactionsTable,
BankAccountsTable,
BankAccountReportsTable,
- BankAccountStatementsTable
+ BankAccountStatementsTable,
+ SandboxConfigsTable,
+ SandboxUsersTable
)
}
}
@@ -337,6 +376,8 @@ fun dbCreateTables(dbConnectionString: String) {
TransactionManager.manager.defaultIsolationLevel =
Connection.TRANSACTION_SERIALIZABLE
transaction {
SchemaUtils.create(
+ SandboxConfigsTable,
+ SandboxUsersTable,
EbicsSubscribersTable,
EbicsHostsTable,
EbicsDownloadTransactionsTable,
diff --git a/sandbox/src/main/kotlin/tech/libeufin/sandbox/Helpers.kt
b/sandbox/src/main/kotlin/tech/libeufin/sandbox/Helpers.kt
index bc9c908..7f7d7aa 100644
--- a/sandbox/src/main/kotlin/tech/libeufin/sandbox/Helpers.kt
+++ b/sandbox/src/main/kotlin/tech/libeufin/sandbox/Helpers.kt
@@ -19,6 +19,9 @@
package tech.libeufin.sandbox
+import com.google.common.io.Resources
+import com.hubspot.jinjava.Jinjava
+import com.hubspot.jinjava.lib.fn.ELFunctionDefinition
import io.ktor.http.HttpStatusCode
import org.jetbrains.exposed.sql.SqlExpressionBuilder.eq
import org.jetbrains.exposed.sql.and
@@ -66,12 +69,33 @@ fun getBankAccountFromLabel(label: String):
BankAccountEntity {
fun getBankAccountFromSubscriber(subscriber: EbicsSubscriberEntity):
BankAccountEntity {
return transaction {
- BankAccountEntity.find(BankAccountsTable.subscriber eq subscriber.id)
- }.firstOrNull() ?: throw SandboxError(
- HttpStatusCode.NotFound,
- "Subscriber doesn't have any bank account"
+ subscriber.bankAccount ?: throw SandboxError(
+ HttpStatusCode.NotFound,
+ "Subscriber doesn't have any bank account"
+ )
+ }
+}
+
+/**
+ * Fetch a configuration for Sandbox, corresponding to the host that runs the
service.
+ */
+fun getSandboxConfig(hostname: String?): SandboxConfigEntity {
+ var ret: SandboxConfigEntity? = transaction {
+ if (hostname == null) {
+ SandboxConfigEntity.all().firstOrNull()
+ } else {
+ SandboxConfigEntity.find {
+ SandboxConfigsTable.hostname eq hostname
+ }.firstOrNull()
+ }
+ }
+ if (ret == null) throw SandboxError(
+ HttpStatusCode.InternalServerError,
+ "Serving from a non configured host"
)
+ return ret
}
+
fun getEbicsSubscriberFromDetails(userID: String, partnerID: String, hostID:
String): EbicsSubscriberEntity {
return transaction {
EbicsSubscriberEntity.find {
@@ -82,4 +106,62 @@ fun getEbicsSubscriberFromDetails(userID: String,
partnerID: String, hostID: Str
"Ebics subscriber not found"
)
}
-}
\ No newline at end of file
+}
+
+/**
+ * FIXME: commenting out until a solution for i18n is found.
+ *
+private fun initJinjava(): Jinjava {
+ class JinjaFunctions {
+ // Used by templates to retrieve configuration values.
+ fun settings_value(name: String): String {
+ return "foo"
+ }
+ fun gettext(translatable: String): String {
+ // temporary, just to make the compiler happy.
+ return translatable
+ }
+ fun url(name: String): String {
+ val map = mapOf<String, String>(
+ "login" to "todo",
+ "profile" to "todo",
+ "register" to "todo",
+ "public-accounts" to "todo"
+ )
+ return map[name] ?: throw
SandboxError(HttpStatusCode.InternalServerError, "URL name unknown")
+ }
+ }
+ val jinjava = Jinjava()
+ val settingsValueFunc = ELFunctionDefinition(
+ "tech.libeufin.sandbox", "settings_value",
+ JinjaFunctions::class.java, "settings_value", String::class.java
+ )
+ val gettextFuncAlias = ELFunctionDefinition(
+ "tech.libeufin.sandbox", "_",
+ JinjaFunctions::class.java, "gettext", String::class.java
+ )
+ val gettextFunc = ELFunctionDefinition(
+ "", "gettext",
+ JinjaFunctions::class.java, "gettext", String::class.java
+ )
+ val urlFunc = ELFunctionDefinition(
+ "tech.libeufin.sandbox", "url",
+ JinjaFunctions::class.java, "url", String::class.java
+ )
+
+ jinjava.globalContext.registerFunction(settingsValueFunc)
+ jinjava.globalContext.registerFunction(gettextFunc)
+ jinjava.globalContext.registerFunction(gettextFuncAlias)
+ jinjava.globalContext.registerFunction(urlFunc)
+
+ return jinjava
+}
+
+val jinjava = initJinjava()
+
+fun renderTemplate(templateName: String, context: Map<String, String>): String
{
+ val template = Resources.toString(Resources.getResource(
+ "templates/$templateName"), Charsets.UTF_8
+ )
+ return jinjava.render(template, context)
+} **/
\ No newline at end of file
diff --git a/sandbox/src/main/kotlin/tech/libeufin/sandbox/Main.kt
b/sandbox/src/main/kotlin/tech/libeufin/sandbox/Main.kt
index 3d96517..2f41e58 100644
--- a/sandbox/src/main/kotlin/tech/libeufin/sandbox/Main.kt
+++ b/sandbox/src/main/kotlin/tech/libeufin/sandbox/Main.kt
@@ -62,6 +62,7 @@ import com.github.ajalt.clikt.core.context
import com.github.ajalt.clikt.core.subcommands
import com.github.ajalt.clikt.output.CliktHelpFormatter
import com.github.ajalt.clikt.parameters.options.default
+import com.github.ajalt.clikt.parameters.options.flag
import com.github.ajalt.clikt.parameters.options.option
import com.github.ajalt.clikt.parameters.options.versionOption
import com.github.ajalt.clikt.parameters.types.int
@@ -86,6 +87,7 @@ import
tech.libeufin.sandbox.BankAccountTransactionsTable.debtorIban
import tech.libeufin.sandbox.BankAccountTransactionsTable.debtorName
import tech.libeufin.sandbox.BankAccountTransactionsTable.direction
import tech.libeufin.sandbox.BankAccountTransactionsTable.pmtInfId
+import tech.libeufin.sandbox.SandboxConfigEntity
import tech.libeufin.util.*
import tech.libeufin.util.ebics_h004.EbicsResponse
import tech.libeufin.util.ebics_h004.EbicsTypes
@@ -102,6 +104,34 @@ data class SandboxError(val statusCode: HttpStatusCode,
val reason: String) : Ex
data class SandboxErrorJson(val error: SandboxErrorDetailJson)
data class SandboxErrorDetailJson(val type: String, val description: String)
+class Config : CliktCommand("Insert one configuration into the database") {
+ init {
+ context {
+ helpFormatter = CliktHelpFormatter(showDefaultValues = true)
+ }
+ }
+
+ private val currencyOption by option().default("EUR")
+ private val bankDebtLimitOption by option().int().default(1000000)
+ private val usersDebtLimitOption by option().int().default(1000)
+ private val allowRegistrationsOption by option().flag(default = true)
+
+ override fun run() {
+ val dbConnString = getDbConnFromEnv(SANDBOX_DB_ENV_VAR_NAME)
+ execThrowableOrTerminate {
+ dbCreateTables(dbConnString)
+ transaction {
+ SandboxConfigEntity.new {
+ currency = currencyOption
+ bankDebtLimit = bankDebtLimitOption
+ usersDebtLimit = usersDebtLimitOption
+ allowRegistrations = allowRegistrationsOption
+ }
+ }
+ }
+ }
+}
+
class ResetTables : CliktCommand("Drop all the tables from the database") {
init {
context {
@@ -201,7 +231,7 @@ class SandboxCommand : CliktCommand(invokeWithoutSubcommand
= true, printHelpOnE
}
fun main(args: Array<String>) {
- SandboxCommand().subcommands(Serve(), ResetTables()).main(args)
+ SandboxCommand().subcommands(Serve(), ResetTables(), Config()).main(args)
}
suspend inline fun <reified T : Any> ApplicationCall.receiveJson(): T {
@@ -227,8 +257,16 @@ fun serverMain(dbName: String, port: Int) {
}
install(Authentication) {
// Web-based authentication for Bank customers.
- form {
-
+ form("auth-form") {
+ userParamName = "username"
+ passwordParamName = "password"
+ validate { credentials ->
+ if (credentials.name == "test") {
+ UserIdPrincipal(credentials.name)
+ } else {
+ null
+ }
+ }
}
}
install(ContentNegotiation) {
@@ -302,6 +340,54 @@ fun serverMain(dbName: String, port: Int) {
}
}
routing {
+ /*
+
+ FIXME: commenting out until a solution for i18n is found.
+
+ get("/bank") {
+ val ret = renderTemplate(
+ "login.html",
+ mapOf("csrf_token" to "todo", )
+ )
+ call.respondText(ret)
+ return@get
+ } */
+
+ post("/register") {
+ // how to read form-POSTed values?
+ val username = "fixme"
+ val password = "fixme"
+ val superuser = false
+
+ transaction {
+ // check if username is taken.
+ var maybeUser = SandboxUserEntity.find {
+ SandboxUsersTable.username eq username
+ }.firstOrNull()
+ // Will be converted to a HTML response.
+ if (maybeUser != null) throw SandboxError(
+ HttpStatusCode.Conflict, "Username not available"
+ )
+
+ // username is valid. Register the user + new bank
account.
+ SandboxUserEntity.new {
+ this.username = username
+ passwordHash = CryptoUtil.hashpw(password)
+ this.superuser = superuser
+ bankAccount = BankAccountEntity.new {
+ iban = "fixme"
+ bic = "fixme"
+ name = "fixme"
+ label = "fixme"
+ currency = "fixme"
+ }
+ }
+ }
+
+ call.respondText("User $username created")
+ return@post
+ }
+
get("/jinja-test") {
val template = Resources.toString(
Resources.getResource("templates/hello.html"),
@@ -313,6 +399,15 @@ fun serverMain(dbName: String, port: Int) {
return@get
}
+ authenticate("auth-form") {
+ get("/profile") {
+ val userSession = call.principal<UserIdPrincipal>()
+ println("Welcoming ${userSession?.name}")
+ call.respond(object {})
+ return@get
+ }
+ }
+
static("/static") {
/**
* Here Sandbox will serve the CSS files.
@@ -400,13 +495,12 @@ fun serverMain(dbName: String, port: Int) {
post("/admin/ebics/bank-accounts") {
val body = call.receiveJson<BankAccountRequest>()
transaction {
- val subscriber = getEbicsSubscriberFromDetails(
+ var subscriber = getEbicsSubscriberFromDetails(
body.subscriber.userID,
body.subscriber.partnerID,
body.subscriber.hostID
)
- BankAccountEntity.new {
- this.subscriber = subscriber
+ subscriber.bankAccount = BankAccountEntity.new {
iban = body.iban
bic = body.bic
name = body.name
@@ -600,6 +694,17 @@ fun serverMain(dbName: String, port: Int) {
}
}
}
+ val configs = transaction {
+ SandboxConfigEntity.all().firstOrNull()
+ }
+ if (configs == null) {
+ logger.error("""
+ Sandbox cannot run without at least one configuration.
+ See "libeufin-sandbox config --help"
+ """.trimIndent()
+ )
+ exitProcess(1)
+ }
logger.info("LibEuFin Sandbox running on port $port")
try {
server.start(wait = true)
--
To stop receiving notification emails like this one, please contact
gnunet@gnunet.org.
- [libeufin] branch master updated (62d0490 -> 786b70a),
gnunet <=
- [libeufin] 05/07: drafting bank config table, gnunet, 2021/06/29
- [libeufin] 07/07: helper that returns a bank configuration, given the hostname., gnunet, 2021/06/29
- [libeufin] 06/07: CLI command to configure the Sandbox, gnunet, 2021/06/29
- [libeufin] 01/07: DB: making Ebics subscriber point at bank accounts., gnunet, 2021/06/29
- [libeufin] 02/07: Commenting out Jinja initialization., gnunet, 2021/06/29
- [libeufin] 03/07: Jinja and form-auth experiments, gnunet, 2021/06/29
- [libeufin] 04/07: drafting user creation, gnunet, 2021/06/29