commit febabaeb08dcb1a51ea0ecb73d8404027081568c
parent 7033a39afafcfa430e5a9bea57ac022f13905e97
Author: Marcello Stanisci <ms@taler.net>
Date: Mon, 11 May 2020 01:56:36 +0200
POST ../bank-transports (incomplete).
Diffstat:
4 files changed, 121 insertions(+), 40 deletions(-)
diff --git a/nexus/src/main/kotlin/tech/libeufin/nexus/DB.kt b/nexus/src/main/kotlin/tech/libeufin/nexus/DB.kt
@@ -177,7 +177,8 @@ class BankAccountEntity(id: EntityID<String>) : Entity<String>(id) {
var bankCode by BankAccountsTable.bankCode
}
-object EbicsSubscribersTable : IntIdTable() {
+object EbicsSubscribersTable : IdTable<String>() {
+ override val id = varchar("id", ID_MAX_LENGTH).entityId().primaryKey()
val ebicsURL = text("ebicsURL")
val hostID = text("hostID")
val partnerID = text("partnerID")
@@ -188,10 +189,11 @@ object EbicsSubscribersTable : IntIdTable() {
val authenticationPrivateKey = blob("authenticationPrivateKey")
val bankEncryptionPublicKey = blob("bankEncryptionPublicKey").nullable()
val bankAuthenticationPublicKey = blob("bankAuthenticationPublicKey").nullable()
+ var nexusUser = reference("nexusUser", NexusUsersTable)
}
-class EbicsSubscriberEntity(id: EntityID<Int>) : Entity<Int>(id) {
- companion object : EntityClass<Int, EbicsSubscriberEntity>(EbicsSubscribersTable)
+class EbicsSubscriberEntity(id: EntityID<String>) : Entity<String>(id) {
+ companion object : EntityClass<String, EbicsSubscriberEntity>(EbicsSubscribersTable)
var ebicsURL by EbicsSubscribersTable.ebicsURL
var hostID by EbicsSubscribersTable.hostID
var partnerID by EbicsSubscribersTable.partnerID
@@ -202,19 +204,16 @@ class EbicsSubscriberEntity(id: EntityID<Int>) : Entity<Int>(id) {
var authenticationPrivateKey by EbicsSubscribersTable.authenticationPrivateKey
var bankEncryptionPublicKey by EbicsSubscribersTable.bankEncryptionPublicKey
var bankAuthenticationPublicKey by EbicsSubscribersTable.bankAuthenticationPublicKey
+ var nexusUser by NexusUserEntity referencedOn EbicsSubscribersTable.nexusUser
}
object NexusUsersTable : IdTable<String>() {
override val id = varchar("id", ID_MAX_LENGTH).entityId()
- val ebicsSubscriber = reference("ebicsSubscriber", EbicsSubscribersTable).nullable()
- val testSubscriber = reference("testSubscriber", EbicsSubscribersTable).nullable()
val password = blob("password").nullable()
}
class NexusUserEntity(id: EntityID<String>) : Entity<String>(id) {
companion object : EntityClass<String, NexusUserEntity>(NexusUsersTable)
- var ebicsSubscriber by EbicsSubscriberEntity optionalReferencedOn NexusUsersTable.ebicsSubscriber
- var testSubscriber by EbicsSubscriberEntity optionalReferencedOn NexusUsersTable.testSubscriber
var password by NexusUsersTable.password
}
diff --git a/nexus/src/main/kotlin/tech/libeufin/nexus/Helpers.kt b/nexus/src/main/kotlin/tech/libeufin/nexus/Helpers.kt
@@ -127,23 +127,8 @@ fun getSubscriberDetailsInternal(subscriber: EbicsSubscriberEntity): EbicsClient
)
}
-/** Return non null Ebics subscriber, or throw error otherwise. */
-fun getEbicsSubscriberFromUser(nexusUser: NexusUserEntity): EbicsSubscriberEntity {
- return nexusUser.ebicsSubscriber ?: throw NexusError(
- HttpStatusCode.NotFound,
- "Ebics subscriber was never activated"
- )
-}
+fun getTransport()
-fun getSubscriberDetailsFromNexusUserId(id: String): EbicsClientSubscriberDetails {
- return transaction {
- val nexusUser = extractNexusUser(id)
- getSubscriberDetailsInternal(nexusUser.ebicsSubscriber ?: throw NexusError(
- HttpStatusCode.NotFound,
- "Cannot get details for non-activated subscriber!"
- ))
- }
-}
/**
* Create a PAIN.001 XML document according to the input data.
diff --git a/nexus/src/main/kotlin/tech/libeufin/nexus/JSON.kt b/nexus/src/main/kotlin/tech/libeufin/nexus/JSON.kt
@@ -32,22 +32,6 @@ data class EbicsDateRangeJson(
val end: String?
)
-/**
- * This object is used twice: as a response to the backup request,
- * and as a request to the backup restore. Note: in the second case
- * the client must provide the passphrase.
- */
-data class EbicsKeysBackupJson(
- val userID: String,
- val partnerID: String,
- val hostID: String,
- val ebicsURL: String,
- val authBlob: String,
- val encBlob: String,
- val sigBlob: String,
- val passphrase: String? = null
-)
-
data class EbicsPubKeyInfo(
val authPub: String,
val encPub: String,
@@ -94,6 +78,36 @@ data class RawPayments(
/*************************************************
* API types (used as requests/responses types) *
*************************************************/
+data class BankTransport(
+ val name: String,
+ val backup: Any, // only EbicsKeysBackupJson exists now.
+ val new: Any,
+ val type: String
+)
+
+/**
+ * This object is used twice: as a response to the backup request,
+ * and as a request to the backup restore. Note: in the second case
+ * the client must provide the passphrase.
+ */
+data class EbicsKeysBackupJson(
+ val userID: String,
+ val partnerID: String,
+ val hostID: String,
+ val ebicsURL: String,
+ val authBlob: String,
+ val encBlob: String,
+ val sigBlob: String,
+ val passphrase: String
+)
+
+data class EbicsNewTransport(
+ val userID: String,
+ val partnerID: String,
+ val hostID: String,
+ val ebicsURL: String,
+ val systemID: String
+)
/** Response type of "GET /prepared-payments/{uuid}" */
data class PaymentStatus(
diff --git a/nexus/src/main/kotlin/tech/libeufin/nexus/Main.kt b/nexus/src/main/kotlin/tech/libeufin/nexus/Main.kt
@@ -52,6 +52,7 @@ import org.slf4j.event.Level
import tech.libeufin.util.*
import java.text.DateFormat
import java.util.zip.InflaterInputStream
+import javax.crypto.EncryptedPrivateKeyInfo
import javax.sql.rowset.serial.SerialBlob
data class NexusError(val statusCode: HttpStatusCode, val reason: String) : Exception()
@@ -197,7 +198,7 @@ fun main() {
val pain001document = createPain001document(preparedPayment)
when (body.transport) {
"ebics" -> {
- val subscriberDetails = getSubscriberDetailsFromNexusUserId(userId)
+ val subscriberDetails = getTransport(body.transport)
logger.debug("Uploading PAIN.001: ${pain001document}")
doEbicsUploadTransaction(
client,
@@ -377,6 +378,7 @@ fun main() {
amount = "${it.currency}:${it.amount}"
)
)
+
}
}
return@get
@@ -385,6 +387,87 @@ fun main() {
* Adds a new bank transport.
*/
post("/bank-transports") {
+ val userId = authenticateRequest(call.request.headers["Authorization"])
+ // user exists and is authenticated.
+ val body = call.receive<BankTransport>()
+ when (body.backup) {
+ is EbicsKeysBackupJson -> {
+ 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"
+ )
+ }
+ logger.info("Restoring keys, creating new user: $userId")
+ try {
+ transaction {
+ EbicsSubscriberEntity.new(userId) {
+ 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)
+ }
+ }
+ } catch (e: Exception) {
+ print(e)
+ call.respond(
+ NexusErrorJson("Could not store the new account into database")
+ )
+ return@post
+ }
+ }
+ }
+ when (body.new) {
+ is EbicsNewTransport -> {
+ val pairA = CryptoUtil.generateRsaKeyPair(2048)
+ val pairB = CryptoUtil.generateRsaKeyPair(2048)
+ val pairC = CryptoUtil.generateRsaKeyPair(2048)
+ transaction {
+ EbicsSubscriberEntity.new {
+ nexusUser = extractNexusUser(userId)
+ ebicsURL = body.new.ebicsURL
+ hostID = body.new.hostID
+ partnerID = body.new.partnerID
+ userID = body.new.userID
+ systemID = body.new.systemID
+ signaturePrivateKey = SerialBlob(pairA.private.encoded)
+ encryptionPrivateKey = SerialBlob(pairB.private.encoded)
+ authenticationPrivateKey = SerialBlob(pairC.private.encoded)
+ }
+ }
+ call.respondText(
+ "EBICS user successfully created",
+ ContentType.Text.Plain,
+ HttpStatusCode.OK
+ )
+ return@post
+ }
+ }
+ call.respond(
+ HttpStatusCode.BadRequest,
+ "Neither backup nor new transport given in request"
+ )
return@post
}
/**