gnunet-svn
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

[libeufin] branch master updated: upgrade dependencies, use ExposedBlob


From: gnunet
Subject: [libeufin] branch master updated: upgrade dependencies, use ExposedBlob instead of SerialBlob
Date: Wed, 03 Jun 2020 09:47:56 +0200

This is an automated email from the git hooks/post-receive script.

dold pushed a commit to branch master
in repository libeufin.

The following commit(s) were added to refs/heads/master by this push:
     new 82133ee  upgrade dependencies, use ExposedBlob instead of SerialBlob
82133ee is described below

commit 82133eede8a316c975231f984bb34d13f08914c7
Author: Florian Dold <florian.dold@gmail.com>
AuthorDate: Wed Jun 3 13:17:50 2020 +0530

    upgrade dependencies, use ExposedBlob instead of SerialBlob
---
 nexus/build.gradle                                 |  9 +-
 nexus/src/main/kotlin/tech/libeufin/nexus/DB.kt    |  6 +-
 .../src/main/kotlin/tech/libeufin/nexus/Helpers.kt | 16 ++--
 nexus/src/main/kotlin/tech/libeufin/nexus/Main.kt  | 38 ++++++---
 nexus/src/main/kotlin/tech/libeufin/nexus/taler.kt | 65 +++++++++------
 sandbox/build.gradle                               |  6 +-
 .../src/main/kotlin/tech/libeufin/sandbox/DB.kt    | 37 ++++++++-
 .../tech/libeufin/sandbox/EbicsProtocolBackend.kt  | 97 +++++++++++-----------
 .../src/main/kotlin/tech/libeufin/sandbox/Main.kt  |  8 +-
 util/build.gradle                                  |  7 +-
 util/src/main/kotlin/DBTypes.kt                    |  4 +-
 util/src/main/kotlin/ParametersChecks.kt           | 40 ---------
 util/src/main/kotlin/blob.kt                       |  7 --
 13 files changed, 179 insertions(+), 161 deletions(-)

diff --git a/nexus/build.gradle b/nexus/build.gradle
index b109726..7d24ab7 100644
--- a/nexus/build.gradle
+++ b/nexus/build.gradle
@@ -54,11 +54,10 @@ compileTestKotlin {
 
 
 def ktor_version = "1.3.2"
-
+def exposed_version = "0.24.1"
 
 dependencies {
     implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk8"
-    implementation "org.jetbrains.exposed:exposed:0.17.6"
     implementation "ch.qos.logback:logback-classic:1.2.3"
     implementation group: 'javax.xml.bind', name: 'jaxb-api', version: '2.3.1'
     implementation "javax.xml.bind:jaxb-api:2.3.0"
@@ -74,6 +73,12 @@ dependencies {
 
     implementation 'org.jetbrains.kotlinx:kotlinx-coroutines-core:1.3.7'
 
+    // Exposed, an SQL library
+    implementation "org.jetbrains.exposed:exposed-core:$exposed_version"
+    implementation "org.jetbrains.exposed:exposed-dao:$exposed_version"
+    implementation "org.jetbrains.exposed:exposed-jdbc:$exposed_version"
+
+    // Ktor, an HTTP client and server library
     implementation "io.ktor:ktor-server-core:$ktor_version"
     implementation "io.ktor:ktor-client-apache:$ktor_version"
     implementation "io.ktor:ktor-server-netty:$ktor_version"
diff --git a/nexus/src/main/kotlin/tech/libeufin/nexus/DB.kt 
b/nexus/src/main/kotlin/tech/libeufin/nexus/DB.kt
index 642daa8..a952f10 100644
--- a/nexus/src/main/kotlin/tech/libeufin/nexus/DB.kt
+++ b/nexus/src/main/kotlin/tech/libeufin/nexus/DB.kt
@@ -2,14 +2,16 @@ package tech.libeufin.nexus
 
 import io.ktor.http.HttpStatusCode
 import org.jetbrains.exposed.dao.*
+import org.jetbrains.exposed.dao.id.LongIdTable
+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.sql.Database
 import org.jetbrains.exposed.sql.SchemaUtils
 import org.jetbrains.exposed.sql.StdOutSqlLogger
 import org.jetbrains.exposed.sql.addLogger
 import org.jetbrains.exposed.sql.transactions.TransactionManager
 import org.jetbrains.exposed.sql.transactions.transaction
-import tech.libeufin.nexus.NexusBankConnectionsTable.entityId
-import tech.libeufin.nexus.NexusBankConnectionsTable.primaryKey
 import tech.libeufin.util.EbicsInitState
 import tech.libeufin.util.amount
 import java.sql.Connection
diff --git a/nexus/src/main/kotlin/tech/libeufin/nexus/Helpers.kt 
b/nexus/src/main/kotlin/tech/libeufin/nexus/Helpers.kt
index 4999851..1462ab9 100644
--- a/nexus/src/main/kotlin/tech/libeufin/nexus/Helpers.kt
+++ b/nexus/src/main/kotlin/tech/libeufin/nexus/Helpers.kt
@@ -5,6 +5,7 @@ import io.ktor.http.HttpStatusCode
 import io.ktor.request.ApplicationRequest
 import org.jetbrains.exposed.sql.SortOrder
 import org.jetbrains.exposed.sql.and
+import org.jetbrains.exposed.sql.statements.api.ExposedBlob
 import org.jetbrains.exposed.sql.transactions.transaction
 import org.w3c.dom.Document
 import tech.libeufin.util.*
@@ -16,7 +17,6 @@ import java.time.ZoneId
 import java.time.ZonedDateTime
 import java.time.format.DateTimeFormatter
 import java.util.*
-import javax.sql.rowset.serial.SerialBlob
 
 fun isProduction(): Boolean {
     return System.getenv("NEXUS_PRODUCTION") != null
@@ -64,13 +64,13 @@ fun getEbicsSubscriberDetailsInternal(subscriber: 
EbicsSubscriberEntity): EbicsC
     var bankAuthPubValue: RSAPublicKey? = null
     if (subscriber.bankAuthenticationPublicKey != null) {
         bankAuthPubValue = CryptoUtil.loadRsaPublicKey(
-            subscriber.bankAuthenticationPublicKey?.toByteArray()!!
+            subscriber.bankAuthenticationPublicKey?.bytes!!
         )
     }
     var bankEncPubValue: RSAPublicKey? = null
     if (subscriber.bankEncryptionPublicKey != null) {
         bankEncPubValue = CryptoUtil.loadRsaPublicKey(
-            subscriber.bankEncryptionPublicKey?.toByteArray()!!
+            subscriber.bankEncryptionPublicKey?.bytes!!
         )
     }
     return EbicsClientSubscriberDetails(
@@ -82,9 +82,9 @@ fun getEbicsSubscriberDetailsInternal(subscriber: 
EbicsSubscriberEntity): EbicsC
         userId = subscriber.userID,
         partnerId = subscriber.partnerID,
 
-        customerSignPriv = 
CryptoUtil.loadRsaPrivateKey(subscriber.signaturePrivateKey.toByteArray()),
-        customerAuthPriv = 
CryptoUtil.loadRsaPrivateKey(subscriber.authenticationPrivateKey.toByteArray()),
-        customerEncPriv = 
CryptoUtil.loadRsaPrivateKey(subscriber.encryptionPrivateKey.toByteArray()),
+        customerSignPriv = 
CryptoUtil.loadRsaPrivateKey(subscriber.signaturePrivateKey.bytes),
+        customerAuthPriv = 
CryptoUtil.loadRsaPrivateKey(subscriber.authenticationPrivateKey.bytes),
+        customerEncPriv = 
CryptoUtil.loadRsaPrivateKey(subscriber.encryptionPrivateKey.bytes),
         ebicsIniState = subscriber.ebicsIniState,
         ebicsHiaState = subscriber.ebicsHiaState
     )
@@ -157,7 +157,7 @@ fun ingestBankMessagesIntoAccount(
                 (NexusBankMessagesTable.id greater 
acct.highestSeenBankMessageId)
         }.orderBy(Pair(NexusBankMessagesTable.id, SortOrder.ASC)).forEach {
             // FIXME: check if it's CAMT first!
-            val doc = 
XMLUtil.parseStringIntoDom(it.message.toByteArray().toString(Charsets.UTF_8))
+            val doc = 
XMLUtil.parseStringIntoDom(it.message.bytes.toString(Charsets.UTF_8))
             processCamtMessage(bankAccountId, doc)
             lastId = it.id.value
         }
@@ -209,7 +209,7 @@ suspend fun fetchEbicsC5x(
                             this.bankConnection = conn
                             this.code = "C53"
                             this.messageId = msgId
-                            this.message = 
SerialBlob(it.second.toByteArray(Charsets.UTF_8))
+                            this.message = 
ExposedBlob(it.second.toByteArray(Charsets.UTF_8))
                         }
                     }
                 }
diff --git a/nexus/src/main/kotlin/tech/libeufin/nexus/Main.kt 
b/nexus/src/main/kotlin/tech/libeufin/nexus/Main.kt
index 1c34f71..fb4d0ba 100644
--- a/nexus/src/main/kotlin/tech/libeufin/nexus/Main.kt
+++ b/nexus/src/main/kotlin/tech/libeufin/nexus/Main.kt
@@ -60,6 +60,7 @@ import kotlinx.coroutines.CoroutineScope
 import kotlinx.coroutines.launch
 import kotlinx.coroutines.time.delay
 import org.jetbrains.exposed.sql.and
+import org.jetbrains.exposed.sql.statements.api.ExposedBlob
 import org.jetbrains.exposed.sql.transactions.transaction
 import org.slf4j.Logger
 import org.slf4j.LoggerFactory
@@ -73,7 +74,6 @@ import java.time.Duration
 import java.util.*
 import java.util.zip.InflaterInputStream
 import javax.crypto.EncryptedPrivateKeyInfo
-import javax.sql.rowset.serial.SerialBlob
 import java.time.LocalDateTime
 
 data class NexusError(val statusCode: HttpStatusCode, val reason: String) :
@@ -176,9 +176,9 @@ fun createEbicsBankConnectionFromBackup(
             hostID = ebicsBackup.hostID
             partnerID = ebicsBackup.partnerID
             userID = ebicsBackup.userID
-            signaturePrivateKey = SerialBlob(sigKey.encoded)
-            encryptionPrivateKey = SerialBlob(encKey.encoded)
-            authenticationPrivateKey = SerialBlob(authKey.encoded)
+            signaturePrivateKey = ExposedBlob(sigKey.encoded)
+            encryptionPrivateKey = ExposedBlob((encKey.encoded))
+            authenticationPrivateKey = ExposedBlob((authKey.encoded))
             nexusBankConnection = bankConn
             ebicsIniState = EbicsInitState.UNKNOWN
             ebicsHiaState = EbicsInitState.UNKNOWN
@@ -222,9 +222,9 @@ fun createEbicsBankConnection(bankConnectionName: String, 
user: NexusUserEntity,
         partnerID = newTransportData.partnerID
         userID = newTransportData.userID
         systemID = newTransportData.systemID
-        signaturePrivateKey = SerialBlob(pairA.private.encoded)
-        encryptionPrivateKey = SerialBlob(pairB.private.encoded)
-        authenticationPrivateKey = SerialBlob(pairC.private.encoded)
+        signaturePrivateKey = ExposedBlob((pairA.private.encoded))
+        encryptionPrivateKey = ExposedBlob((pairB.private.encoded))
+        authenticationPrivateKey = ExposedBlob((pairC.private.encoded))
         nexusBankConnection = bankConn
         ebicsIniState = EbicsInitState.NOT_SENT
         ebicsHiaState = EbicsInitState.NOT_SENT
@@ -278,6 +278,18 @@ suspend fun downloadFacadesTransactions(coroutineScope: 
CoroutineScope) {
     }
 }
 
+fun <T>expectNonNull(param: T?): T {
+    return param ?: throw EbicsProtocolError(
+        HttpStatusCode.BadRequest,
+        "Non-null value expected."
+    )
+}
+
+fun ApplicationCall.expectUrlParameter(name: String): String {
+    return this.request.queryParameters[name]
+        ?: throw EbicsProtocolError(HttpStatusCode.BadRequest, "Parameter 
'$name' not provided in URI")
+}
+
 suspend fun fetchTransactionsInternal(
     client: HttpClient,
     user: NexusUserEntity,
@@ -860,8 +872,8 @@ fun serverMain(dbName: String) {
                         subscriberEntity.ebicsHiaState = EbicsInitState.SENT
                     }
                     if (hpbData != null) {
-                        subscriberEntity.bankAuthenticationPublicKey = 
SerialBlob(hpbData.authenticationPubKey.encoded)
-                        subscriberEntity.bankEncryptionPublicKey = 
SerialBlob(hpbData.encryptionPubKey.encoded)
+                        subscriberEntity.bankAuthenticationPublicKey = 
ExposedBlob((hpbData.authenticationPubKey.encoded))
+                        subscriberEntity.bankEncryptionPublicKey = 
ExposedBlob((hpbData.encryptionPubKey.encoded))
                     }
                 }
                 call.respond(object {})
@@ -872,7 +884,7 @@ fun serverMain(dbName: String) {
                     val list = BankMessageList()
                     val conn = requireBankConnection(call, "connid")
                     NexusBankMessageEntity.find { 
NexusBankMessagesTable.bankConnection eq conn.id }.map {
-                        list.bankMessages.add(BankMessageInfo(it.messageId, 
it.code, it.message.length()))
+                        list.bankMessages.add(BankMessageInfo(it.messageId, 
it.code, it.message.bytes.size.toLong()))
                     }
                     list
                 }
@@ -890,7 +902,7 @@ fun serverMain(dbName: String) {
                         throw NexusError(HttpStatusCode.NotFound, "bank 
message not found")
                     }
                     return@transaction object {
-                        val msgContent = msg.message.toByteArray()
+                        val msgContent = msg.message.bytes
                     }
                 }
                 call.respondBytes(ret.msgContent, ContentType("application", 
"xml"))
@@ -974,8 +986,8 @@ fun serverMain(dbName: String) {
                     val conn = requireBankConnection(call, "connid")
                     val subscriber =
                         EbicsSubscriberEntity.find { 
EbicsSubscribersTable.nexusBankConnection eq conn.id }.first()
-                    subscriber.bankAuthenticationPublicKey = 
SerialBlob(hpbData.authenticationPubKey.encoded)
-                    subscriber.bankEncryptionPublicKey = 
SerialBlob(hpbData.encryptionPubKey.encoded)
+                    subscriber.bankAuthenticationPublicKey = 
ExposedBlob((hpbData.authenticationPubKey.encoded))
+                    subscriber.bankEncryptionPublicKey = 
ExposedBlob((hpbData.encryptionPubKey.encoded))
                 }
                 call.respond(object {})
             }
diff --git a/nexus/src/main/kotlin/tech/libeufin/nexus/taler.kt 
b/nexus/src/main/kotlin/tech/libeufin/nexus/taler.kt
index a1a4b00..de7ea14 100644
--- a/nexus/src/main/kotlin/tech/libeufin/nexus/taler.kt
+++ b/nexus/src/main/kotlin/tech/libeufin/nexus/taler.kt
@@ -12,16 +12,13 @@ import io.ktor.response.respondText
 import io.ktor.routing.Route
 import io.ktor.routing.get
 import io.ktor.routing.post
-import org.apache.http.client.methods.RequestBuilder.post
 import org.jetbrains.exposed.dao.Entity
-import org.jetbrains.exposed.dao.IdTable
+import org.jetbrains.exposed.dao.id.IdTable
 import org.jetbrains.exposed.sql.*
-import org.jetbrains.exposed.sql.SqlExpressionBuilder.eq
 import org.jetbrains.exposed.sql.transactions.transaction
-import tech.libeufin.util.*
-import java.time.LocalDateTime
-import java.time.ZoneId
-import java.util.concurrent.atomic.LongAdder
+import tech.libeufin.util.CryptoUtil
+import tech.libeufin.util.EbicsProtocolError
+import tech.libeufin.util.parseAmount
 import kotlin.math.abs
 import kotlin.math.min
 
@@ -53,6 +50,7 @@ data class TalerIncomingBankTransaction(
 data class TalerIncomingHistory(
     var incoming_transactions: MutableList<TalerIncomingBankTransaction> = 
mutableListOf()
 )
+
 data class TalerOutgoingBankTransaction(
     val row_id: Long,
     val date: GnunetTimestamp, // timestamp
@@ -83,6 +81,7 @@ data class TalerAdminAddIncoming(
 data class GnunetTimestamp(
     val t_ms: Long
 )
+
 data class TalerAddIncomingResponse(
     val timestamp: GnunetTimestamp,
     val row_id: Long
@@ -146,6 +145,7 @@ fun <T : Entity<Long>> SizedIterable<T>.orderTaler(delta: 
Int): List<T> {
 fun buildPaytoUri(name: String, iban: String, bic: String): String {
     return "payto://iban/$bic/$iban?name=$name"
 }
+
 fun buildPaytoUri(iban: String, bic: String): String {
     return "payto://iban/$bic/$iban"
 }
@@ -162,23 +162,22 @@ fun getComparisonOperator(delta: Int, start: Long, table: 
IdTable<Long>): Op<Boo
         }
     }
 }
+
+fun expectLong(param: String?): Long {
+    if (param == null) {
+        throw EbicsProtocolError(HttpStatusCode.BadRequest, "'$param' is not 
Long")
+    }
+    return try {
+        param.toLong()
+    } catch (e: Exception) {
+        throw EbicsProtocolError(HttpStatusCode.BadRequest, "'$param' is not 
Long")
+    }
+}
+
+
 /** Helper handling 'start' being optional and its dependence on 'delta'.  */
 fun handleStartArgument(start: String?, delta: Int): Long {
-    return expectLong(start) ?: if (delta >= 0) {
-        /**
-         * Using -1 as the smallest value, as some DBMS might use 0 and some
-         * others might use 1 as the smallest row id.
-         */
-        -1
-    } else {
-        /**
-         * NOTE: the database currently enforces there MAX_VALUE is always
-         * strictly greater than any row's id in the database.  In fact, the
-         * database throws exception whenever a new row is going to occupy
-         * the MAX_VALUE with its id.
-         */
-        Long.MAX_VALUE
-    }
+    return expectLong(start)
 }
 
 /**
@@ -405,13 +404,19 @@ fun ingestTalerTransactions() {
 }
 
 suspend fun historyOutgoing(call: ApplicationCall): Unit {
-    val delta: Int = expectInt(call.expectUrlParameter("delta"))
+    val param = call.expectUrlParameter("delta")
+    val delta: Int = try {
+        param.toInt()
+    } catch (e: Exception) {
+        throw EbicsProtocolError(HttpStatusCode.BadRequest, "'${param}' is not 
Int")
+    }
     val start: Long = 
handleStartArgument(call.request.queryParameters["start"], delta)
     val startCmpOp = getComparisonOperator(delta, start, 
TalerRequestedPayments)
     /* retrieve database elements */
     val history = TalerOutgoingHistory()
     transaction {
         val user = authenticateRequest(call.request)
+
         /** Retrieve all the outgoing payments from the _clean Taler outgoing 
table_ */
         val subscriberBankAccount = getFacadeBankAccount(user)
         val reqPayments = TalerRequestedPaymentEntity.find {
@@ -424,8 +429,11 @@ suspend fun historyOutgoing(call: ApplicationCall): Unit {
                         row_id = it.id.value,
                         amount = it.amount,
                         wtid = it.wtid,
-                        date = 
GnunetTimestamp(it.rawConfirmed?.bookingDate?.div(1000) ?: throw NexusError(
-                            HttpStatusCode.InternalServerError, "Null value 
met after check, VERY strange.")),
+                        date = GnunetTimestamp(
+                            it.rawConfirmed?.bookingDate?.div(1000) ?: throw 
NexusError(
+                                HttpStatusCode.InternalServerError, "Null 
value met after check, VERY strange."
+                            )
+                        ),
                         credit_account = it.creditAccount,
                         debit_account = 
buildPaytoUri(subscriberBankAccount.iban, subscriberBankAccount.bankCode),
                         exchange_base_url = 
"FIXME-to-request-along-subscriber-registration"
@@ -442,7 +450,12 @@ suspend fun historyOutgoing(call: ApplicationCall): Unit {
 
 // /taler/history/incoming
 suspend fun historyIncoming(call: ApplicationCall): Unit {
-    val delta: Int = expectInt(call.expectUrlParameter("delta"))
+    val param = call.expectUrlParameter("delta")
+    val delta: Int = try {
+        param.toInt()
+    } catch (e: Exception) {
+        throw EbicsProtocolError(HttpStatusCode.BadRequest, "'${param}' is not 
Int")
+    }
     val start: Long = 
handleStartArgument(call.request.queryParameters["start"], delta)
     val history = TalerIncomingHistory()
     val startCmpOp = getComparisonOperator(delta, start, TalerIncomingPayments)
diff --git a/sandbox/build.gradle b/sandbox/build.gradle
index ae550cb..19bcb51 100644
--- a/sandbox/build.gradle
+++ b/sandbox/build.gradle
@@ -41,10 +41,10 @@ sourceSets {
 }
 
 def ktor_version = "1.3.2"
+def exposed_version = "0.24.1"
 
 dependencies {
     implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk8"
-    implementation "org.jetbrains.exposed:exposed:0.17.6"
     implementation "ch.qos.logback:logback-classic:1.2.3"
     implementation group: 'javax.xml.bind', name: 'jaxb-api', version: '2.3.1'
     implementation "javax.xml.bind:jaxb-api:2.3.0"
@@ -56,6 +56,10 @@ dependencies {
     implementation group: 'org.xerial', name: 'sqlite-jdbc', version: '3.28.0'
     implementation group: 'org.apache.commons', name: 'commons-compress', 
version: '1.20'
 
+    implementation "org.jetbrains.exposed:exposed-core:$exposed_version"
+    implementation "org.jetbrains.exposed:exposed-dao:$exposed_version"
+    implementation "org.jetbrains.exposed:exposed-jdbc:$exposed_version"
+
     implementation "io.ktor:ktor-server-core:$ktor_version"
     implementation "io.ktor:ktor-client-apache:$ktor_version"
     implementation "io.ktor:ktor-server-netty:$ktor_version"
diff --git a/sandbox/src/main/kotlin/tech/libeufin/sandbox/DB.kt 
b/sandbox/src/main/kotlin/tech/libeufin/sandbox/DB.kt
index 9e7d7dd..de11908 100644
--- a/sandbox/src/main/kotlin/tech/libeufin/sandbox/DB.kt
+++ b/sandbox/src/main/kotlin/tech/libeufin/sandbox/DB.kt
@@ -19,8 +19,17 @@
 
 package tech.libeufin.sandbox
 
-import org.jetbrains.exposed.dao.*
-import org.jetbrains.exposed.sql.*
+import org.jetbrains.exposed.dao.Entity
+import org.jetbrains.exposed.dao.EntityClass
+import org.jetbrains.exposed.dao.IntEntity
+import org.jetbrains.exposed.dao.IntEntityClass
+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.sql.Database
+import org.jetbrains.exposed.sql.SchemaUtils
+import org.jetbrains.exposed.sql.StdOutSqlLogger
+import org.jetbrains.exposed.sql.addLogger
 import org.jetbrains.exposed.sql.transactions.TransactionManager
 import org.jetbrains.exposed.sql.transactions.transaction
 import java.sql.Connection
@@ -85,6 +94,7 @@ object EbicsSubscriberPublicKeysTable : IntIdTable() {
     val rsaPublicKey = blob("rsaPublicKey")
     val state = enumeration("state", KeyState::class)
 }
+
 class EbicsSubscriberPublicKeyEntity(id: EntityID<Int>) : IntEntity(id) {
     companion object : 
IntEntityClass<EbicsSubscriberPublicKeyEntity>(EbicsSubscriberPublicKeysTable)
 
@@ -102,8 +112,10 @@ object EbicsHostsTable : IntIdTable() {
     val encryptionPrivateKey = blob("encryptionPrivateKey")
     val authenticationPrivateKey = blob("authenticationPrivateKey")
 }
+
 class EbicsHostEntity(id: EntityID<Int>) : IntEntity(id) {
     companion object : IntEntityClass<EbicsHostEntity>(EbicsHostsTable)
+
     var hostId by EbicsHostsTable.hostID
     var ebicsVersion by EbicsHostsTable.ebicsVersion
     var signaturePrivateKey by EbicsHostsTable.signaturePrivateKey
@@ -125,8 +137,10 @@ object EbicsSubscribersTable : IntIdTable() {
     val nextOrderID = integer("nextOrderID")
     val state = enumeration("state", SubscriberState::class)
 }
+
 class EbicsSubscriberEntity(id: EntityID<Int>) : IntEntity(id) {
     companion object : 
IntEntityClass<EbicsSubscriberEntity>(EbicsSubscribersTable)
+
     var userId by EbicsSubscribersTable.userId
     var partnerId by EbicsSubscribersTable.partnerId
     var systemId by EbicsSubscribersTable.systemId
@@ -152,8 +166,10 @@ object EbicsDownloadTransactionsTable : IdTable<String>() {
     val segmentSize = integer("segmentSize")
     val receiptReceived = bool("receiptReceived")
 }
+
 class EbicsDownloadTransactionEntity(id: EntityID<String>) : 
Entity<String>(id) {
     companion object : EntityClass<String, 
EbicsDownloadTransactionEntity>(EbicsDownloadTransactionsTable)
+
     var orderType by EbicsDownloadTransactionsTable.orderType
     var host by EbicsHostEntity referencedOn 
EbicsDownloadTransactionsTable.host
     var subscriber by EbicsSubscriberEntity referencedOn 
EbicsDownloadTransactionsTable.subscriber
@@ -177,8 +193,10 @@ object EbicsUploadTransactionsTable : IdTable<String>() {
     val lastSeenSegment = integer("lastSeenSegment")
     val transactionKeyEnc = blob("transactionKeyEnc")
 }
+
 class EbicsUploadTransactionEntity(id: EntityID<String>) : Entity<String>(id) {
     companion object : EntityClass<String, 
EbicsUploadTransactionEntity>(EbicsUploadTransactionsTable)
+
     var orderType by EbicsUploadTransactionsTable.orderType
     var orderID by EbicsUploadTransactionsTable.orderID
     var host by EbicsHostEntity referencedOn EbicsUploadTransactionsTable.host
@@ -199,8 +217,10 @@ object EbicsOrderSignaturesTable : IntIdTable() {
     val signatureAlgorithm = text("signatureAlgorithm")
     val signatureValue = blob("signatureValue")
 }
+
 class EbicsOrderSignatureEntity(id: EntityID<Int>) : IntEntity(id) {
     companion object : 
IntEntityClass<EbicsOrderSignatureEntity>(EbicsOrderSignaturesTable)
+
     var orderID by EbicsOrderSignaturesTable.orderID
     var orderType by EbicsOrderSignaturesTable.orderType
     var partnerID by EbicsOrderSignaturesTable.partnerID
@@ -218,8 +238,10 @@ object EbicsUploadTransactionChunksTable : 
IdTable<String>() {
     val chunkIndex = integer("chunkIndex")
     val chunkContent = blob("chunkContent")
 }
+
 class EbicsUploadTransactionChunkEntity(id: EntityID<String>) : 
Entity<String>(id) {
     companion object : EntityClass<String, 
EbicsUploadTransactionChunkEntity>(EbicsUploadTransactionChunksTable)
+
     var chunkIndex by EbicsUploadTransactionChunksTable.chunkIndex
     var chunkContent by EbicsUploadTransactionChunksTable.chunkContent
 }
@@ -234,13 +256,18 @@ object PaymentsTable : IntIdTable() {
     val amount = text("amount")
     val date = long("date")
 }
+
 class PaymentEntity(id: EntityID<Int>) : IntEntity(id) {
     companion object : IntEntityClass<PaymentEntity>(PaymentsTable)
+
     var creditorIban by PaymentsTable.creditorIban
     var debitorIban by PaymentsTable.debitorIban
     var subject by PaymentsTable.subject
-    var amount by PaymentsTable.amount /** in the CURRENCY:X.Y format */
-    var date by PaymentsTable.date /** Date when the payment was persisted in 
this system.  */
+    var amount by PaymentsTable.amount
+
+    /** in the CURRENCY:X.Y format */
+    var date by PaymentsTable.date
+    /** Date when the payment was persisted in this system.  */
 }
 
 /**
@@ -254,8 +281,10 @@ object BankAccountsTable : IntIdTable() {
     val label = text("label")
     val subscriber = reference("subscriber", EbicsSubscribersTable)
 }
+
 class BankAccountEntity(id: EntityID<Int>) : IntEntity(id) {
     companion object : IntEntityClass<BankAccountEntity>(BankAccountsTable)
+
     var iban by BankAccountsTable.iban
     var bic by BankAccountsTable.bic
     var name by BankAccountsTable.name
diff --git 
a/sandbox/src/main/kotlin/tech/libeufin/sandbox/EbicsProtocolBackend.kt 
b/sandbox/src/main/kotlin/tech/libeufin/sandbox/EbicsProtocolBackend.kt
index 30de622..2134fee 100644
--- a/sandbox/src/main/kotlin/tech/libeufin/sandbox/EbicsProtocolBackend.kt
+++ b/sandbox/src/main/kotlin/tech/libeufin/sandbox/EbicsProtocolBackend.kt
@@ -28,38 +28,23 @@ import io.ktor.response.respond
 import io.ktor.response.respondText
 import org.apache.xml.security.binding.xmldsig.RSAKeyValueType
 import org.jetbrains.exposed.sql.*
+import org.jetbrains.exposed.sql.statements.api.ExposedBlob
 import org.jetbrains.exposed.sql.transactions.transaction
 import org.w3c.dom.Document
+import tech.libeufin.util.*
+import tech.libeufin.util.XMLUtil.Companion.signEbicsResponse
 import tech.libeufin.util.ebics_h004.*
 import tech.libeufin.util.ebics_hev.HEVResponse
 import tech.libeufin.util.ebics_hev.SystemReturnCodeType
 import tech.libeufin.util.ebics_s001.SignatureTypes
 import tech.libeufin.util.ebics_s001.UserSignatureData
-import tech.libeufin.util.CryptoUtil
-import tech.libeufin.util.EbicsOrderUtil
-import tech.libeufin.util.XMLUtil
-import tech.libeufin.util.*
-import tech.libeufin.util.XMLUtil.Companion.signEbicsResponse
-import java.io.ByteArrayOutputStream
-import java.math.BigDecimal
 import java.security.interfaces.RSAPrivateCrtKey
 import java.security.interfaces.RSAPublicKey
+import java.time.Instant
+import java.time.LocalDateTime
 import java.util.*
 import java.util.zip.DeflaterInputStream
 import java.util.zip.InflaterInputStream
-import javax.sql.rowset.serial.SerialBlob
-import javax.xml.datatype.DatatypeFactory
-import org.apache.commons.compress.utils.IOUtils
-import org.jetbrains.exposed.sql.SqlExpressionBuilder.eq
-import java.io.BufferedInputStream
-import java.io.ByteArrayInputStream
-import java.nio.charset.Charset
-import java.time.Instant
-import java.time.LocalDateTime
-import java.time.ZoneId
-import java.time.ZonedDateTime
-import java.time.format.DateTimeFormatter
-import javax.xml.datatype.XMLGregorianCalendar
 
 
 open class EbicsRequestError(errorText: String, errorCode: String) :
@@ -142,6 +127,13 @@ private suspend fun 
ApplicationCall.respondEbicsKeyManagement(
     respondText(text, ContentType.Application.Xml, HttpStatusCode.OK)
 }
 
+fun <T>expectNonNull(x: T?): T {
+    if (x == null) {
+        throw EbicsProtocolError(HttpStatusCode.BadRequest, "expected non-null 
value")
+    }
+    return x;
+}
+
 /**
  * Returns a list of camt strings.  Note: each element in the
  * list accounts for only one payment in the history.  In other
@@ -172,7 +164,10 @@ fun buildCamtString(type: Int, history: 
MutableList<RawPayment>): MutableList<St
                 root("Document") {
                     attribute("xmlns", 
"urn:iso:std:iso:20022:tech:xsd:camt.053.001.02")
                     attribute("xmlns:xsi", 
"http://www.w3.org/2001/XMLSchema-instance";)
-                    attribute("xsi:schemaLocation", 
"urn:iso:std:iso:20022:tech:xsd:camt.053.001.02 camt.053.001.02.xsd")
+                    attribute(
+                        "xsi:schemaLocation",
+                        "urn:iso:std:iso:20022:tech:xsd:camt.053.001.02 
camt.053.001.02.xsd"
+                    )
                     element("BkToCstmrStmt") {
                         element("GrpHdr") {
                             element("MsgId") {
@@ -418,10 +413,11 @@ private fun constructCamtResponse(
     transaction {
         PaymentEntity.find {
             PaymentsTable.creditorIban eq bankAccount.iban or
-                    (PaymentsTable.debitorIban eq bankAccount.iban) /**
-                     FIXME!
-                     and (PaymentsTable.date.between(start.millis, end.millis))
-                     */
+                    (PaymentsTable.debitorIban eq bankAccount.iban)
+            /**
+            FIXME!
+            and (PaymentsTable.date.between(start.millis, end.millis))
+             */
         }.forEach {
             history.add(
                 RawPayment(
@@ -504,11 +500,11 @@ private suspend fun 
ApplicationCall.handleEbicsHia(header: EbicsUnsecuredRequest
             throw EbicsInvalidRequestError()
         }
         ebicsSubscriber.authenticationKey = EbicsSubscriberPublicKeyEntity.new 
{
-            this.rsaPublicKey = SerialBlob(authPub.encoded)
+            this.rsaPublicKey = ExposedBlob(authPub.encoded)
             state = KeyState.NEW
         }
         ebicsSubscriber.encryptionKey = EbicsSubscriberPublicKeyEntity.new {
-            this.rsaPublicKey = SerialBlob(encPub.encoded)
+            this.rsaPublicKey = ExposedBlob(encPub.encoded)
             state = KeyState.NEW
         }
         ebicsSubscriber.state = when (ebicsSubscriber.state) {
@@ -539,7 +535,7 @@ private suspend fun ApplicationCall.handleEbicsIni(header: 
EbicsUnsecuredRequest
             throw EbicsInvalidRequestError()
         }
         ebicsSubscriber.signatureKey = EbicsSubscriberPublicKeyEntity.new {
-            this.rsaPublicKey = SerialBlob(sigPub.encoded)
+            this.rsaPublicKey = ExposedBlob(sigPub.encoded)
             state = KeyState.NEW
         }
         ebicsSubscriber.state = when (ebicsSubscriber.state) {
@@ -570,16 +566,16 @@ private suspend fun ApplicationCall.handleEbicsHpb(
         val encPubBlob = ebicsSubscriber.encryptionKey!!.rsaPublicKey
         val sigPubBlob = ebicsSubscriber.signatureKey!!.rsaPublicKey
         SubscriberKeys(
-            CryptoUtil.loadRsaPublicKey(authPubBlob.toByteArray()),
-            CryptoUtil.loadRsaPublicKey(encPubBlob.toByteArray()),
-            CryptoUtil.loadRsaPublicKey(sigPubBlob.toByteArray())
+            CryptoUtil.loadRsaPublicKey(authPubBlob.bytes),
+            CryptoUtil.loadRsaPublicKey(encPubBlob.bytes),
+            CryptoUtil.loadRsaPublicKey(sigPubBlob.bytes)
         )
     }
     val validationResult =
         XMLUtil.verifyEbicsDocument(requestDocument, 
subscriberKeys.authenticationPublicKey)
     LOGGER.info("validationResult: $validationResult")
     if (!validationResult) {
-        throw EbicsKeyManagementError("invalid signature", "90000");
+        throw EbicsKeyManagementError("invalid signature", "90000")
     }
     val hpbRespondeData = HPBResponseOrderData().apply {
         this.authenticationPubKeyInfo = 
EbicsTypes.AuthenticationPubKeyInfoType().apply {
@@ -622,8 +618,8 @@ private fun ApplicationCall.ensureEbicsHost(requestHostID: 
String): EbicsHostPub
             LOGGER.warn("client requested unknown HostID ${requestHostID}")
             throw EbicsKeyManagementError("[EBICS_INVALID_HOST_ID]", "091011")
         }
-        val encryptionPrivateKey = 
CryptoUtil.loadRsaPrivateKey(ebicsHost.encryptionPrivateKey.toByteArray())
-        val authenticationPrivateKey = 
CryptoUtil.loadRsaPrivateKey(ebicsHost.authenticationPrivateKey.toByteArray())
+        val encryptionPrivateKey = 
CryptoUtil.loadRsaPrivateKey(ebicsHost.encryptionPrivateKey.bytes)
+        val authenticationPrivateKey = 
CryptoUtil.loadRsaPrivateKey(ebicsHost.authenticationPrivateKey.bytes)
         EbicsHostPublicInfo(
             requestHostID,
             CryptoUtil.getRsaPublicFromPrivate(encryptionPrivateKey),
@@ -797,7 +793,7 @@ private fun 
handleEbicsDownloadTransactionInitialization(requestContext: Request
         this.host = requestContext.ebicsHost
         this.orderType = orderType
         this.segmentSize = segmentSize
-        this.transactionKeyEnc = SerialBlob(enc.encryptedTransactionKey)
+        this.transactionKeyEnc = ExposedBlob(enc.encryptedTransactionKey)
         this.encodedResponse = encodedResponse
         this.numSegments = numSegments
         this.receiptReceived = false
@@ -847,7 +843,7 @@ private fun 
handleEbicsUploadTransactionInitialization(requestContext: RequestCo
         this.orderType = orderType
         this.orderID = orderID
         this.numSegments = numSegments.toInt()
-        this.transactionKeyEnc = SerialBlob(transactionKeyEnc)
+        this.transactionKeyEnc = ExposedBlob(transactionKeyEnc)
     }
     val sigObj = 
XMLUtil.convertStringToJaxb<UserSignatureData>(plainSigData.toString(Charsets.UTF_8))
     println("got UserSignatureData: ${plainSigData.toString(Charsets.UTF_8)}")
@@ -859,7 +855,7 @@ private fun 
handleEbicsUploadTransactionInitialization(requestContext: RequestCo
             this.partnerID = sig.partnerID
             this.userID = sig.userID
             this.signatureAlgorithm = sig.signatureVersion
-            this.signatureValue = SerialBlob(sig.signatureValue)
+            this.signatureValue = ExposedBlob(sig.signatureValue)
         }
     }
     return EbicsResponse.createForUploadInitializationPhase(transactionID, 
orderID)
@@ -875,7 +871,7 @@ private fun 
handleEbicsUploadTransactionTransmission(requestContext: RequestCont
         val encOrderData =
             requestObject.body.dataTransfer?.orderData ?: throw 
EbicsInvalidRequestError()
         val zippedData = CryptoUtil.decryptEbicsE002(
-            uploadTransaction.transactionKeyEnc.toByteArray(),
+            uploadTransaction.transactionKeyEnc.bytes,
             Base64.getDecoder().decode(encOrderData),
             requestContext.hostEncPriv
         )
@@ -883,18 +879,22 @@ private fun 
handleEbicsUploadTransactionTransmission(requestContext: RequestCont
             InflaterInputStream(zippedData.inputStream()).use { 
it.readAllBytes() }
         logger.debug("got upload data: 
${unzippedData.toString(Charsets.UTF_8)}")
 
-        val sigs  = EbicsOrderSignatureEntity.find {
+        val sigs = EbicsOrderSignatureEntity.find {
             (EbicsOrderSignaturesTable.orderID eq uploadTransaction.orderID) 
and
                     (EbicsOrderSignaturesTable.orderType eq 
uploadTransaction.orderType)
         }
-        if (sigs.count() == 0) {
+        if (sigs.count() == 0L) {
             throw EbicsInvalidRequestError()
         }
         for (sig in sigs) {
             if (sig.signatureAlgorithm == "A006") {
 
                 val signedData = CryptoUtil.digestEbicsOrderA006(unzippedData)
-                val res1 = 
CryptoUtil.verifyEbicsA006(sig.signatureValue.toByteArray(), signedData, 
requestContext.clientSigPub)
+                val res1 = CryptoUtil.verifyEbicsA006(
+                    sig.signatureValue.bytes,
+                    signedData,
+                    requestContext.clientSigPub
+                )
 
                 if (!res1) {
                     throw EbicsInvalidRequestError()
@@ -954,19 +954,17 @@ private fun makeReqestContext(requestObject: 
EbicsRequest): RequestContext {
         throw EbicsSubscriberStateError()
 
     val hostAuthPriv = CryptoUtil.loadRsaPrivateKey(
-        ebicsHost.authenticationPrivateKey
-            .toByteArray()
+        ebicsHost.authenticationPrivateKey.bytes
     )
     val hostEncPriv = CryptoUtil.loadRsaPrivateKey(
-        ebicsHost.encryptionPrivateKey
-            .toByteArray()
+        ebicsHost.encryptionPrivateKey.bytes
     )
     val clientAuthPub =
-        
CryptoUtil.loadRsaPublicKey(subscriber.authenticationKey!!.rsaPublicKey.toByteArray())
+        
CryptoUtil.loadRsaPublicKey(subscriber.authenticationKey!!.rsaPublicKey.bytes)
     val clientEncPub =
-        
CryptoUtil.loadRsaPublicKey(subscriber.encryptionKey!!.rsaPublicKey.toByteArray())
+        
CryptoUtil.loadRsaPublicKey(subscriber.encryptionKey!!.rsaPublicKey.bytes)
     val clientSigPub =
-        
CryptoUtil.loadRsaPublicKey(subscriber.signatureKey!!.rsaPublicKey.toByteArray())
+        
CryptoUtil.loadRsaPublicKey(subscriber.signatureKey!!.rsaPublicKey.bytes)
 
     return RequestContext(
         hostAuthPriv = hostAuthPriv,
@@ -1056,7 +1054,8 @@ suspend fun ApplicationCall.ebicsweb() {
                         }
                     }
                     EbicsTypes.TransactionPhaseType.RECEIPT -> {
-                        val requestTransactionID = 
requestObject.header.static.transactionID ?: throw EbicsInvalidRequestError()
+                        val requestTransactionID =
+                            requestObject.header.static.transactionID ?: throw 
EbicsInvalidRequestError()
                         if (requestContext.downloadTransaction == null)
                             throw EbicsInvalidRequestError()
                         val receiptCode =
diff --git a/sandbox/src/main/kotlin/tech/libeufin/sandbox/Main.kt 
b/sandbox/src/main/kotlin/tech/libeufin/sandbox/Main.kt
index 884804a..b525aed 100644
--- a/sandbox/src/main/kotlin/tech/libeufin/sandbox/Main.kt
+++ b/sandbox/src/main/kotlin/tech/libeufin/sandbox/Main.kt
@@ -50,7 +50,6 @@ import java.lang.ArithmeticException
 import java.math.BigDecimal
 import java.security.interfaces.RSAPublicKey
 import java.text.DateFormat
-import javax.sql.rowset.serial.SerialBlob
 import javax.xml.bind.JAXBContext
 import com.fasterxml.jackson.core.util.DefaultIndenter
 import com.fasterxml.jackson.core.util.DefaultPrettyPrinter
@@ -61,6 +60,7 @@ import com.fasterxml.jackson.module.kotlin.KotlinModule
 import com.fasterxml.jackson.module.kotlin.MissingKotlinParameterException
 import com.fasterxml.jackson.module.kotlin.jacksonObjectMapper
 import io.ktor.http.toHttpDateString
+import org.jetbrains.exposed.sql.statements.api.ExposedBlob
 import java.time.Instant
 import java.time.LocalDate
 import java.time.LocalDateTime
@@ -272,9 +272,9 @@ fun main() {
                     EbicsHostEntity.new {
                         this.ebicsVersion = req.ebicsVersion
                         this.hostId = req.hostID
-                        this.authenticationPrivateKey = 
SerialBlob(pairA.private.encoded)
-                        this.encryptionPrivateKey = 
SerialBlob(pairB.private.encoded)
-                        this.signaturePrivateKey = 
SerialBlob(pairC.private.encoded)
+                        this.authenticationPrivateKey = 
ExposedBlob(pairA.private.encoded)
+                        this.encryptionPrivateKey = 
ExposedBlob(pairB.private.encoded)
+                        this.signaturePrivateKey = 
ExposedBlob(pairC.private.encoded)
 
                     }
                 }
diff --git a/util/build.gradle b/util/build.gradle
index d06ff1b..fb647bb 100644
--- a/util/build.gradle
+++ b/util/build.gradle
@@ -26,9 +26,10 @@ sourceSets {
     main.java.srcDirs = ['src/main/java', 'src/main/kotlin']
 }
 
+def exposed_version = "0.24.1"
+
 dependencies {
     implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk8"
-    implementation "org.jetbrains.exposed:exposed:0.17.6"
     implementation "io.ktor:ktor-server-netty:1.2.4"
     implementation "ch.qos.logback:logback-classic:1.2.3"
     implementation group: 'javax.xml.bind', name: 'jaxb-api', version: '2.3.1'
@@ -38,9 +39,11 @@ dependencies {
     implementation "org.glassfish.jaxb:jaxb-runtime:2.3.1"
     implementation 'org.apache.santuario:xmlsec:2.1.4'
     implementation group: 'org.bouncycastle', name: 'bcprov-jdk15on', version: 
'1.64'
-    implementation group: 'org.xerial', name: 'sqlite-jdbc', version: '3.28.0'
     implementation group: 'org.apache.commons', name: 'commons-compress', 
version: '1.20'
 
+    implementation "org.jetbrains.exposed:exposed-core:$exposed_version"
+    implementation "org.jetbrains.exposed:exposed-dao:$exposed_version"
+
     testImplementation group: 'junit', name: 'junit', version: '4.12'
     testImplementation 'org.jetbrains.kotlin:kotlin-test-junit:1.3.50'
     testImplementation 'org.jetbrains.kotlin:kotlin-test:1.3.50'
diff --git a/util/src/main/kotlin/DBTypes.kt b/util/src/main/kotlin/DBTypes.kt
index f86b70b..69f36af 100644
--- a/util/src/main/kotlin/DBTypes.kt
+++ b/util/src/main/kotlin/DBTypes.kt
@@ -1,7 +1,5 @@
 package tech.libeufin.util
 
-import org.jetbrains.exposed.dao.IdTable
-import org.jetbrains.exposed.dao.IntIdTable
 import org.jetbrains.exposed.sql.Column
 import org.jetbrains.exposed.sql.ColumnType
 import org.jetbrains.exposed.sql.Table
@@ -58,6 +56,6 @@ class AmountColumnType : ColumnType() {
  * Make sure the number entered by upper layers does not need any rounding
  * to conform to scale == 2
  */
-fun IdTable<*>.amount(name: String): Column<Amount> {
+fun Table.amount(name: String): Column<Amount> {
     return registerColumn(name, AmountColumnType())
 }
\ No newline at end of file
diff --git a/util/src/main/kotlin/ParametersChecks.kt 
b/util/src/main/kotlin/ParametersChecks.kt
deleted file mode 100644
index 64e4963..0000000
--- a/util/src/main/kotlin/ParametersChecks.kt
+++ /dev/null
@@ -1,40 +0,0 @@
-package tech.libeufin.util
-
-import io.ktor.application.ApplicationCall
-import io.ktor.http.HttpStatusCode
-
-fun expectInt(param: String): Int {
-    return try {
-        param.toInt()
-    } catch (e: Exception) {
-        throw EbicsProtocolError(HttpStatusCode.BadRequest,"'$param' is not 
Int")
-    }
-}
-
-fun <T>expectNonNull(param: T?): T {
-    return param ?: throw EbicsProtocolError(
-        HttpStatusCode.BadRequest,
-        "Non-null value expected."
-    )
-}
-
-fun expectLong(param: String): Long {
-    return try {
-        param.toLong()
-    } catch (e: Exception) {
-        throw EbicsProtocolError(HttpStatusCode.BadRequest,"'$param' is not 
Long")
-    }
-}
-
-fun expectLong(param: String?): Long? {
-    if (param != null) {
-        return expectLong(param)
-    }
-    return null
-}
-
-
-fun ApplicationCall.expectUrlParameter(name: String): String {
-    return this.request.queryParameters[name]
-        ?: throw EbicsProtocolError(HttpStatusCode.BadRequest, "Parameter 
'$name' not provided in URI")
-}
\ No newline at end of file
diff --git a/util/src/main/kotlin/blob.kt b/util/src/main/kotlin/blob.kt
deleted file mode 100644
index ee50335..0000000
--- a/util/src/main/kotlin/blob.kt
+++ /dev/null
@@ -1,7 +0,0 @@
-package tech.libeufin.util
-
-import java.sql.Blob
-
-fun Blob.toByteArray(): ByteArray {
-    return this.binaryStream.readAllBytes()
-}
\ No newline at end of file

-- 
To stop receiving notification emails like this one, please contact
gnunet@gnunet.org.



reply via email to

[Prev in Thread] Current Thread [Next in Thread]