summaryrefslogtreecommitdiff
path: root/nexus/src/main
diff options
context:
space:
mode:
authorMS <ms@taler.net>2020-05-14 17:47:23 +0200
committerMS <ms@taler.net>2020-05-14 17:47:23 +0200
commit8f118987a6fe292e1fd5a7d16fe0baf63a5f3240 (patch)
tree623e03f29a9c2b0d99ccdcafd76a898ddc618615 /nexus/src/main
parent24d03f3e49848a2109d02ad9b6d19ad72a633dad (diff)
downloadlibeufin-8f118987a6fe292e1fd5a7d16fe0baf63a5f3240.tar.gz
libeufin-8f118987a6fe292e1fd5a7d16fe0baf63a5f3240.tar.bz2
libeufin-8f118987a6fe292e1fd5a7d16fe0baf63a5f3240.zip
Overloading POST ../bank-transport.
Plus getting the Taler facade to compile again.
Diffstat (limited to 'nexus/src/main')
-rw-r--r--nexus/src/main/kotlin/tech/libeufin/nexus/Helpers.kt21
-rw-r--r--nexus/src/main/kotlin/tech/libeufin/nexus/JSON.kt10
-rw-r--r--nexus/src/main/kotlin/tech/libeufin/nexus/Main.kt159
-rw-r--r--nexus/src/main/kotlin/tech/libeufin/nexus/taler.kt86
4 files changed, 154 insertions, 122 deletions
diff --git a/nexus/src/main/kotlin/tech/libeufin/nexus/Helpers.kt b/nexus/src/main/kotlin/tech/libeufin/nexus/Helpers.kt
index 93e5eb94..135d53ba 100644
--- a/nexus/src/main/kotlin/tech/libeufin/nexus/Helpers.kt
+++ b/nexus/src/main/kotlin/tech/libeufin/nexus/Helpers.kt
@@ -1,5 +1,7 @@
package tech.libeufin.nexus
+import com.google.gson.Gson
+import com.google.gson.JsonObject
import io.ktor.client.HttpClient
import io.ktor.http.HttpStatusCode
import org.jetbrains.exposed.sql.and
@@ -60,6 +62,12 @@ fun extractFirstBic(bankCodes: List<EbicsTypes.AbstractBankCode>?): String? {
return null
}
+fun getTransportFromJsonObject(jo: JsonObject): Transport {
+ return Gson().fromJson(
+ expectNonNull(jo.get("transport")).asJsonObject, Transport::class.java
+ )
+}
+
/**
* Retrieve bank account details, only if user owns it.
*/
@@ -128,7 +136,7 @@ fun getEbicsSubscriberDetailsInternal(subscriber: EbicsSubscriberEntity): EbicsC
)
}
-fun getEbicsTransport(userId: String, transportId: String?): EbicsSubscriberEntity {
+fun getEbicsTransport(userId: String, transportId: String? = null): EbicsSubscriberEntity {
val transport = transaction {
if (transportId == null) {
return@transaction EbicsSubscriberEntity.all().first()
@@ -150,7 +158,7 @@ fun getEbicsTransport(userId: String, transportId: String?): EbicsSubscriberEnti
/**
* Retrieve Ebics subscriber details given a Transport
- * object and handling the default case.
+ * object and handling the default case (when this latter is null).
*/
fun getEbicsSubscriberDetails(userId: String, transportId: String?): EbicsClientSubscriberDetails {
val transport = getEbicsTransport(userId, transportId)
@@ -370,6 +378,15 @@ fun getPreparedPayment(uuid: String): PreparedPaymentEntity {
)
}
+fun getNexusUser(id: String): NexusUserEntity {
+ return transaction {
+ NexusUserEntity.findById(id)
+ } ?: throw NexusError(
+ HttpStatusCode.NotFound,
+ "User '$id' not found"
+ )
+}
+
/**
* Insert one row in the database, and leaves it marked as non-submitted.
* @param debtorAccountId the mnemonic id assigned by the bank to one bank
diff --git a/nexus/src/main/kotlin/tech/libeufin/nexus/JSON.kt b/nexus/src/main/kotlin/tech/libeufin/nexus/JSON.kt
index 2a8f72d2..8f27ec94 100644
--- a/nexus/src/main/kotlin/tech/libeufin/nexus/JSON.kt
+++ b/nexus/src/main/kotlin/tech/libeufin/nexus/JSON.kt
@@ -1,8 +1,6 @@
package tech.libeufin.nexus
-import com.sun.jdi.connect.Transport
import tech.libeufin.util.*
-import java.lang.NullPointerException
import java.time.LocalDate
data class EbicsBackupRequestJson(
@@ -79,10 +77,10 @@ data class RawPayments(
/*************************************************
* API types (used as requests/responses types) *
*************************************************/
-data class BankTransport<T, S>(
- val transport: tech.libeufin.nexus.Transport,
- val backup: T?,
- val data: S?
+data class BankTransport(
+ val transport: Transport,
+ val backup: Any? = null,
+ val data: Any?
)
/**
diff --git a/nexus/src/main/kotlin/tech/libeufin/nexus/Main.kt b/nexus/src/main/kotlin/tech/libeufin/nexus/Main.kt
index 488dce7b..43db3b26 100644
--- a/nexus/src/main/kotlin/tech/libeufin/nexus/Main.kt
+++ b/nexus/src/main/kotlin/tech/libeufin/nexus/Main.kt
@@ -19,6 +19,8 @@
package tech.libeufin.nexus
+import com.google.gson.Gson
+import com.google.gson.JsonObject
import io.ktor.application.ApplicationCallPipeline
import io.ktor.application.call
import io.ktor.application.install
@@ -404,88 +406,99 @@ fun main() {
post("/bank-transports") {
val userId = authenticateRequest(call.request.headers["Authorization"])
// user exists and is authenticated.
- val body = call.receive<BankTransport>()
- logger.debug("Request body parsed")
- when (body.backup) {
- is EbicsKeysBackupJson -> {
- logger.debug("Restoring a transport: ${body.transport.name}")
- val (authKey, encKey, sigKey) = try {
- Triple(
- CryptoUtil.decryptKey(
- EncryptedPrivateKeyInfo(base64ToBytes(body.backup.authBlob)),
- body.backup.passphrase
- ),
- CryptoUtil.decryptKey(
- EncryptedPrivateKeyInfo(base64ToBytes(body.backup.encBlob)),
- body.backup.passphrase
- ),
- CryptoUtil.decryptKey(
- EncryptedPrivateKeyInfo(base64ToBytes(body.backup.sigBlob)),
- body.backup.passphrase
- )
- )
- } catch (e: Exception) {
- e.printStackTrace()
- logger.info("Restoring keys failed, probably due to wrong passphrase")
- throw NexusError(
- HttpStatusCode.BadRequest,
- "Bad backup given"
+ val body = call.receive<JsonObject>()
+ val transport: Transport = getTransportFromJsonObject(body)
+ when (transport.type) {
+ "ebics" -> {
+ if (body.get("backup") != null) {
+ val backup = Gson().fromJson(
+ body.get("backup").asJsonObject,
+ EbicsKeysBackupJson::class.java
)
+ val (authKey, encKey, sigKey) = try {
+ Triple(
+ CryptoUtil.decryptKey(
+ EncryptedPrivateKeyInfo(base64ToBytes(backup.authBlob)),
+ backup.passphrase
+ ),
+ CryptoUtil.decryptKey(
+ EncryptedPrivateKeyInfo(base64ToBytes(backup.encBlob)),
+ backup.passphrase
+ ),
+ CryptoUtil.decryptKey(
+ EncryptedPrivateKeyInfo(base64ToBytes(backup.sigBlob)),
+ backup.passphrase
+ )
+ )
+ } catch (e: Exception) {
+ e.printStackTrace()
+ logger.info("Restoring keys failed, probably due to wrong passphrase")
+ throw NexusError(
+ HttpStatusCode.BadRequest,
+ "Bad backup given"
+ )
+ }
+ logger.info("Restoring keys, creating new user: $userId")
+ try {
+ transaction {
+ EbicsSubscriberEntity.new(transport.name) {
+ this.nexusUser = extractNexusUser(userId)
+ ebicsURL = backup.ebicsURL
+ hostID = backup.hostID
+ partnerID = backup.partnerID
+ userID = backup.userID
+ signaturePrivateKey = SerialBlob(sigKey.encoded)
+ encryptionPrivateKey = SerialBlob(encKey.encoded)
+ authenticationPrivateKey = SerialBlob(authKey.encoded)
+ }
+ }
+ } catch (e: Exception) {
+ print(e)
+ call.respond(
+ NexusErrorJson("Could not store the new account into database")
+ )
+ return@post
+ }
+ call.respondText("Backup restored")
+
+ return@post
}
- logger.info("Restoring keys, creating new user: $userId")
- try {
+ if (body.get("data") != null) {
+ val data = Gson().fromJson(
+ body.get("data"),
+ EbicsNewTransport::class.java
+ )
+ val pairA = CryptoUtil.generateRsaKeyPair(2048)
+ val pairB = CryptoUtil.generateRsaKeyPair(2048)
+ val pairC = CryptoUtil.generateRsaKeyPair(2048)
transaction {
- EbicsSubscriberEntity.new(body.transport.name) {
- this.nexusUser = extractNexusUser(userId)
- ebicsURL = body.backup.ebicsURL
- hostID = body.backup.hostID
- partnerID = body.backup.partnerID
- userID = body.backup.userID
- signaturePrivateKey = SerialBlob(sigKey.encoded)
- encryptionPrivateKey = SerialBlob(encKey.encoded)
- authenticationPrivateKey = SerialBlob(authKey.encoded)
+ EbicsSubscriberEntity.new(transport.name) {
+ nexusUser = extractNexusUser(userId)
+ ebicsURL = data.ebicsURL
+ hostID = data.hostID
+ partnerID = data.partnerID
+ userID = data.userID
+ systemID = data.systemID
+ signaturePrivateKey = SerialBlob(pairA.private.encoded)
+ encryptionPrivateKey = SerialBlob(pairB.private.encoded)
+ authenticationPrivateKey = SerialBlob(pairC.private.encoded)
}
}
- } catch (e: Exception) {
- print(e)
- call.respond(
- NexusErrorJson("Could not store the new account into database")
- )
+ call.respondText("EBICS user successfully created")
return@post
}
- call.respondText("Backup restored")
- return@post
+ throw NexusError(
+ HttpStatusCode.BadRequest,
+ "Neither restore or new transport were specified."
+ )
}
- }
- when (body.data) {
- is EbicsNewTransport -> {
- logger.debug("Creating new transport: ${body.transport.name}")
- val pairA = CryptoUtil.generateRsaKeyPair(2048)
- val pairB = CryptoUtil.generateRsaKeyPair(2048)
- val pairC = CryptoUtil.generateRsaKeyPair(2048)
- transaction {
- EbicsSubscriberEntity.new(body.transport.name) {
- nexusUser = extractNexusUser(userId)
- ebicsURL = body.data.ebicsURL
- hostID = body.data.hostID
- partnerID = body.data.partnerID
- userID = body.data.userID
- systemID = body.data.systemID
- signaturePrivateKey = SerialBlob(pairA.private.encoded)
- encryptionPrivateKey = SerialBlob(pairB.private.encoded)
- authenticationPrivateKey = SerialBlob(pairC.private.encoded)
- }
- }
- call.respondText("EBICS user successfully created")
- return@post
+ else -> {
+ throw NexusError(
+ HttpStatusCode.BadRequest,
+ "Invalid transport type '${transport.type}'"
+ )
}
- } // end of second 'when'.
-
- call.respond(
- HttpStatusCode.BadRequest,
- "Neither backup nor new transport given in request"
- )
- return@post
+ }
}
/**
* Sends to the bank a message "MSG" according to the transport
diff --git a/nexus/src/main/kotlin/tech/libeufin/nexus/taler.kt b/nexus/src/main/kotlin/tech/libeufin/nexus/taler.kt
index b259bb51..f3dd6148 100644
--- a/nexus/src/main/kotlin/tech/libeufin/nexus/taler.kt
+++ b/nexus/src/main/kotlin/tech/libeufin/nexus/taler.kt
@@ -226,7 +226,7 @@ class Taler(app: Route) {
val creditorObj = parsePayto(transferRequest.credit_account)
val opaque_row_id = transaction {
val creditorData = parsePayto(transferRequest.credit_account)
- val exchangeBankAccount = getBankAccountFromNexusUserId(exchangeId)
+ val exchangeBankAccount = getBankAccountsFromNexusUserId(exchangeId).first()
val nexusUser = extractNexusUser(exchangeId)
/** Checking the UID has the desired characteristics */
TalerRequestedPaymentEntity.find {
@@ -251,9 +251,7 @@ class Taler(app: Route) {
subject = transferRequest.wtid,
sum = amountObj.amount,
currency = amountObj.currency,
- debitorName = exchangeBankAccount.accountHolder,
- debitorBic = exchangeBankAccount.bankCode,
- debitorIban = exchangeBankAccount.iban
+ debitorAccount = exchangeBankAccount.id.value
),
nexusUser
)
@@ -264,11 +262,10 @@ class Taler(app: Route) {
transactionType = "DBIT"
currency = amountObj.currency
this.amount = amountObj.amount.toPlainString()
- debitorName = "Exchange Company"
- debitorIban = exchangeBankAccount.iban
- creditorName = creditorObj.name
- creditorIban = creditorObj.iban
counterpartBic = creditorObj.bic
+ counterpartIban = creditorObj.iban
+ counterpartName = creditorObj.name
+ bankAccount = exchangeBankAccount
bookingDate = DateTime.now().millis
this.nexusUser = nexusUser
status = "BOOK"
@@ -312,21 +309,20 @@ class Taler(app: Route) {
val debtor = parsePayto(addIncomingData.debit_account)
val amount = parseAmount(addIncomingData.amount)
val (bookingDate, opaque_row_id) = transaction {
- val exchangeBankAccount = getBankAccountFromNexusUserId(exchangeId)
+ val exchangeBankAccount = getBankAccountsFromNexusUserId(exchangeId).first()
val rawPayment = RawBankTransactionEntity.new {
sourceFileName = "test"
unstructuredRemittanceInformation = addIncomingData.reserve_pub
transactionType = "CRDT"
currency = amount.currency
this.amount = amount.amount.toPlainString()
- creditorIban = exchangeBankAccount.iban
- creditorName = exchangeBankAccount.accountHolder
- debitorIban = debtor.iban
- debitorName = debtor.name
counterpartBic = debtor.bic
+ counterpartName = debtor.name
+ counterpartIban = debtor.iban
bookingDate = DateTime.now().millis
status = "BOOK"
nexusUser = extractNexusUser(exchangeId)
+ bankAccount = exchangeBankAccount
}
/** This payment is "valid by default" and will be returned
* as soon as the exchange will ask for new payments. */
@@ -355,30 +351,26 @@ class Taler(app: Route) {
* places it into a further table. Eventually, another routine will perform
* all the prepared payments. */
app.post("/ebics/taler/{id}/accounts/{acctid}/refund-invalid-payments") {
+ val userId = authenticateRequest(call.request.headers["Authorization"])
+ val nexusUser = getNexusUser(userId)
+ val callerBankAccount = expectNonNull(call.parameters["acctid"])
transaction {
- val nexusUser = extractNexusUser(call.parameters["id"])
- val acctid = expectAcctidTransaction(call.parameters["acctid"])
- if (!subscriberHasRights(getEbicsSubscriberFromUser(nexusUser), acctid)) {
- throw NexusError(
- HttpStatusCode.Forbidden,
- "The requester can't drive such account (${acctid.id})"
- )
- }
- val requesterBankAccount = getBankAccountFromNexusUserId(nexusUser.id.value)
+ val bankAccount = getBankAccount(
+ userId,
+ callerBankAccount
+ )
TalerIncomingPaymentEntity.find {
TalerIncomingPayments.refunded eq false and (TalerIncomingPayments.valid eq false)
}.forEach {
addPreparedPayment(
Pain001Data(
- creditorName = it.payment.debitorName,
- creditorIban = it.payment.debitorIban,
+ creditorName = it.payment.counterpartName,
+ creditorIban = it.payment.counterpartIban,
creditorBic = it.payment.counterpartBic,
sum = calculateRefund(it.payment.amount),
subject = "Taler refund",
- debitorIban = requesterBankAccount.iban,
- debitorBic = requesterBankAccount.bankCode,
- debitorName = requesterBankAccount.accountHolder,
- currency = it.payment.currency
+ currency = it.payment.currency,
+ debitorAccount = callerBankAccount
),
nexusUser
)
@@ -398,18 +390,22 @@ class Taler(app: Route) {
val id = ensureNonNull(call.parameters["id"])
// first find highest ID value of already processed rows.
transaction {
- val subscriberAccount = getBankAccountFromNexusUserId(id)
+ val subscriberAccount = getBankAccountsFromNexusUserId(id).first()
/**
* Search for fresh incoming payments in the raw table, and making pointers
- * from the Taler incoming payments table to the found fresh payments.
+ * from the Taler incoming payments table to the found fresh (and valid!) payments.
*/
val latestIncomingPaymentId: Long = TalerIncomingPaymentEntity.getLast()
RawBankTransactionEntity.find {
- /** select payments having the exchange as the credited party */
- RawBankTransactionsTable.creditorIban eq subscriberAccount.iban and
+ /** Those with exchange bank account involved */
+ RawBankTransactionsTable.bankAccount eq subscriberAccount.id.value and
+ /** Those that are incoming */
+ (RawBankTransactionsTable.transactionType eq "CRDT") and
+ /** Those that are booked */
(RawBankTransactionsTable.status eq "BOOK") and
- /** avoid processing old payments from the raw table */
+ /** Those that came later than the latest processed payment */
(RawBankTransactionsTable.id.greater(latestIncomingPaymentId))
+
}.forEach {
if (duplicatePayment(it)) {
logger.warn("Incomint payment already seen")
@@ -437,8 +433,12 @@ class Taler(app: Route) {
*/
val latestOutgoingPaymentId = TalerRequestedPaymentEntity.getLast()
RawBankTransactionEntity.find {
+ /** Those that came after the last processed payment */
RawBankTransactionsTable.id greater latestOutgoingPaymentId and
- ( RawBankTransactionsTable.debitorIban eq subscriberAccount.iban)
+ /** Those involving the exchange bank account */
+ (RawBankTransactionsTable.bankAccount eq subscriberAccount.id.value) and
+ /** Those that are outgoing */
+ (RawBankTransactionsTable.transactionType eq "DBIT")
}.forEach {
if (paymentFailed(it)) {
logger.error("Bank didn't accept one payment from the exchange")
@@ -485,7 +485,7 @@ class Taler(app: Route) {
val history = TalerOutgoingHistory()
transaction {
/** Retrieve all the outgoing payments from the _clean Taler outgoing table_ */
- val subscriberBankAccount = getBankAccountFromNexusUserId(subscriberId)
+ val subscriberBankAccount = getBankAccountsFromNexusUserId(subscriberId).first()
val reqPayments = TalerRequestedPaymentEntity.find {
TalerRequestedPayments.rawConfirmed.isNotNull() and startCmpOp
}.orderTaler(delta)
@@ -539,12 +539,12 @@ class Taler(app: Route) {
val nexusUser = extractNexusUser(exchangeId)
BankAccountMapEntity.new {
bankAccount = newBankAccount
- ebicsSubscriber = getEbicsSubscriberFromUser(nexusUser)
+ ebicsSubscriber = getEbicsTransport(exchangeId)
this.nexusUser = nexusUser
}
}
}
- val exchangeBankAccount = getBankAccountFromNexusUserId(exchangeId)
+ val exchangeBankAccount = getBankAccountsFromNexusUserId(exchangeId).first()
val orderedPayments = TalerIncomingPaymentEntity.find {
TalerIncomingPayments.valid eq true and startCmpOp
}.orderTaler(delta)
@@ -556,11 +556,15 @@ class Taler(app: Route) {
row_id = it.id.value,
amount = "${it.payment.currency}:${it.payment.amount}",
reserve_pub = it.payment.unstructuredRemittanceInformation,
- debit_account = buildPaytoUri(
- it.payment.debitorName, it.payment.debitorIban, it.payment.counterpartBic
- ),
credit_account = buildPaytoUri(
- it.payment.creditorName, it.payment.creditorIban, exchangeBankAccount.bankCode
+ it.payment.bankAccount.accountHolder,
+ it.payment.bankAccount.iban,
+ it.payment.bankAccount.bankCode
+ ),
+ debit_account = buildPaytoUri(
+ it.payment.counterpartName,
+ it.payment.counterpartIban,
+ it.payment.counterpartBic
)
)
)