diff options
author | Antoine A <> | 2024-03-04 11:08:08 +0100 |
---|---|---|
committer | Antoine A <> | 2024-03-04 11:08:08 +0100 |
commit | 4f2f3926822a3574d1fba96c20b0c159754d9f98 (patch) | |
tree | 4fabd2024d5af73dfd9a75124e5c291d31720c15 | |
parent | 769d458c8de9e38f77a599f9301290624280bb92 (diff) | |
download | libeufin-4f2f3926822a3574d1fba96c20b0c159754d9f98.tar.gz libeufin-4f2f3926822a3574d1fba96c20b0c159754d9f98.tar.bz2 libeufin-4f2f3926822a3574d1fba96c20b0c159754d9f98.zip |
Improve ack parsing and logging
7 files changed, 56 insertions, 50 deletions
diff --git a/ebics/src/main/kotlin/Ebics.kt b/ebics/src/main/kotlin/Ebics.kt index 31efa07c..ab591b61 100644 --- a/ebics/src/main/kotlin/Ebics.kt +++ b/ebics/src/main/kotlin/Ebics.kt @@ -287,6 +287,7 @@ enum class EbicsReturnCode(val errorCode: String) { data class EbicsResponseContent( val transactionID: String?, + val orderID: String?, val dataEncryptionInfo: DataEncryptionInfo?, val orderDataEncChunk: String?, val technicalReturnCode: EbicsReturnCode, @@ -362,6 +363,7 @@ fun ebics3toInternalRepr(response: Document): EbicsResponseContent { return EbicsResponseContent( transactionID = resp.value.header._static.transactionID, + orderID = resp.value.header.mutable.orderID, bankReturnCode = bankReturnCode, technicalReturnCode = techReturnCode, reportText = reportText, @@ -398,6 +400,7 @@ fun ebics25toInternalRepr(response: Document): EbicsResponseContent { return EbicsResponseContent( transactionID = resp.value.header._static.transactionID, + orderID = resp.value.header.mutable.orderID, bankReturnCode = bankReturnCode, technicalReturnCode = techReturnCode, reportText = reportText, diff --git a/nexus/src/main/kotlin/tech/libeufin/nexus/Database.kt b/nexus/src/main/kotlin/tech/libeufin/nexus/Database.kt index 956ae58c..8a2b9185 100644 --- a/nexus/src/main/kotlin/tech/libeufin/nexus/Database.kt +++ b/nexus/src/main/kotlin/tech/libeufin/nexus/Database.kt @@ -169,6 +169,9 @@ private fun PreparedStatement.maybeUpdate(): Boolean { */ class Database(dbConfig: String): DbPool(dbConfig, "libeufin_nexus") { + // Temporary in memory database to store EBICS order status until we modify the schema to actually store it in the database + var mem: MutableMap<String, String> = mutableMapOf() + // OUTGOING PAYMENTS METHODS /** diff --git a/nexus/src/main/kotlin/tech/libeufin/nexus/EbicsFetch.kt b/nexus/src/main/kotlin/tech/libeufin/nexus/EbicsFetch.kt index f4298287..e8d4b049 100644 --- a/nexus/src/main/kotlin/tech/libeufin/nexus/EbicsFetch.kt +++ b/nexus/src/main/kotlin/tech/libeufin/nexus/EbicsFetch.kt @@ -230,6 +230,17 @@ private fun ingestDocument( SupportedDocument.PAIN_002_LOGS -> { val acks = parseCustomerAck(xml) for (ack in acks) { + val msg = if (ack.orderId != null) { + if (ack.code != null) { + val msg = ack.msg() + db.mem[ack.orderId] = msg + msg + } else { + db.mem[ack.orderId] + } + } else { + null + } when (ack.actionType) { HacAction.FILE_DOWNLOAD -> logger.debug("$ack") HacAction.ORDER_HAC_FINAL_POS -> { @@ -240,7 +251,7 @@ private fun ingestDocument( HacAction.ORDER_HAC_FINAL_NEG -> { // TODO update pending transaction status logger.debug("$ack") - logger.warn("Order '${ack.orderId}' was refused at ${ack.timestamp.fmtDateTime()}") + logger.warn("Order '${ack.orderId}' was refused at ${ack.timestamp.fmtDateTime()}: $msg") } else -> { // TODO update pending transaction status diff --git a/nexus/src/main/kotlin/tech/libeufin/nexus/EbicsSubmit.kt b/nexus/src/main/kotlin/tech/libeufin/nexus/EbicsSubmit.kt index e96e3db2..ce02f865 100644 --- a/nexus/src/main/kotlin/tech/libeufin/nexus/EbicsSubmit.kt +++ b/nexus/src/main/kotlin/tech/libeufin/nexus/EbicsSubmit.kt @@ -91,7 +91,7 @@ class NexusSubmitException( private suspend fun submitInitiatedPayment( ctx: SubmissionContext, payment: InitiatedPayment -) { +): String { val creditAccount = try { val payto = Payto.parse(payment.creditPaytoUri).expectIban() IbanAccountMetadata( @@ -114,7 +114,7 @@ private suspend fun submitInitiatedPayment( ) ctx.fileLogger.logSubmit(xml) try { - submitPain001( + return submitPain001( xml, ctx.cfg, ctx.clientPrivateKeysFile, @@ -166,7 +166,8 @@ private fun submitBatch( db.initiatedPaymentsSubmittableGet(ctx.cfg.currency).forEach { logger.debug("Submitting payment initiation with row ID: ${it.id}") val submissionState = try { - submitInitiatedPayment(ctx, it) + val orderId = submitInitiatedPayment(ctx, it) + db.mem[orderId] = "Init" DatabaseSubmissionState.success } catch (e: NexusSubmitException) { logger.error(e.message) diff --git a/nexus/src/main/kotlin/tech/libeufin/nexus/Iso20022.kt b/nexus/src/main/kotlin/tech/libeufin/nexus/Iso20022.kt index 53cfdf80..fb9c03ce 100644 --- a/nexus/src/main/kotlin/tech/libeufin/nexus/Iso20022.kt +++ b/nexus/src/main/kotlin/tech/libeufin/nexus/Iso20022.kt @@ -129,15 +129,19 @@ data class CustomerAck( val code: ExternalStatusReasonCode?, val timestamp: Instant ) { - override fun toString(): String { - var str = "${timestamp.fmtDateTime()}" - if (orderId != null) str += " ${orderId}" - str += " ${actionType}" + fun msg(): String { + var str = "${actionType}" if (code != null) str += " ${code.isoCode}" str += " - '${actionType.description}'" if (code != null) str += " '${code.description}'" return str } + + override fun toString(): String { + var str = "${timestamp.fmtDateTime()}" + if (orderId != null) str += " ${orderId}" + return str + " ${msg()}" + } } /** diff --git a/nexus/src/main/kotlin/tech/libeufin/nexus/ebics/Ebics3.kt b/nexus/src/main/kotlin/tech/libeufin/nexus/ebics/Ebics3.kt index 52bdeb0b..09aac3df 100644 --- a/nexus/src/main/kotlin/tech/libeufin/nexus/ebics/Ebics3.kt +++ b/nexus/src/main/kotlin/tech/libeufin/nexus/ebics/Ebics3.kt @@ -234,7 +234,7 @@ suspend fun submitPain001( clientKeys: ClientPrivateKeysFile, bankkeys: BankPublicKeysFile, httpClient: HttpClient -) { +): String { val orderService: Ebics3Request.OrderDetails.Service = Ebics3Request.OrderDetails.Service().apply { serviceName = "MCT" scope = "CH" @@ -255,6 +255,7 @@ suspend fun submitPain001( " EBICS technical code is: ${maybeUploaded.technicalReturnCode}," + " bank technical return code is: ${maybeUploaded.bankReturnCode}" ) + return maybeUploaded.orderID!! } /** diff --git a/nexus/src/main/kotlin/tech/libeufin/nexus/ebics/EbicsCommon.kt b/nexus/src/main/kotlin/tech/libeufin/nexus/ebics/EbicsCommon.kt index f497799e..7eebcea8 100644 --- a/nexus/src/main/kotlin/tech/libeufin/nexus/ebics/EbicsCommon.kt +++ b/nexus/src/main/kotlin/tech/libeufin/nexus/ebics/EbicsCommon.kt @@ -225,11 +225,30 @@ suspend fun postEbics( e ) } - return parseAndValidateEbicsResponse( - bankKeys, - respXml, + + // Parses the bank response from the raw XML and verifies + // the bank signature. + val doc = try { + XMLUtil.parseIntoDom(respXml) + } catch (e: Exception) { + throw EbicsSideException( + "Bank response apparently invalid", + sideEc = EbicsSideError.BANK_RESPONSE_IS_INVALID + ) + } + if (!XMLUtil.verifyEbicsDocument( + doc, + bankKeys.bank_authentication_public_key, isEbics3 - ) + )) { + throw EbicsSideException( + "Bank signature did not verify", + sideEc = EbicsSideError.BANK_SIGNATURE_DIDNT_VERIFY + ) + } + if (isEbics3) + return ebics3toInternalRepr(doc) + return ebics25toInternalRepr(doc) } /** @@ -384,43 +403,6 @@ class EbicsSideException( ) : Exception(msg, cause) /** - * Parses the bank response from the raw XML and verifies - * the bank signature. - * - * @param bankKeys provides the bank auth pub, to verify the signature. - * @param responseStr raw XML response from the bank - * @param withEbics3 true if the communication is EBICS 3, false otherwise. - * @return [EbicsResponseContent] or throw [EbicsSideException] - */ -fun parseAndValidateEbicsResponse( - bankKeys: BankPublicKeysFile, - resp: InputStream, - withEbics3: Boolean -): EbicsResponseContent { - val doc = try { - XMLUtil.parseIntoDom(resp) - } catch (e: Exception) { - throw EbicsSideException( - "Bank response apparently invalid", - sideEc = EbicsSideError.BANK_RESPONSE_IS_INVALID - ) - } - if (!XMLUtil.verifyEbicsDocument( - doc, - bankKeys.bank_authentication_public_key, - withEbics3 - )) { - throw EbicsSideException( - "Bank signature did not verify", - sideEc = EbicsSideError.BANK_SIGNATURE_DIDNT_VERIFY - ) - } - if (withEbics3) - return ebics3toInternalRepr(doc) - return ebics25toInternalRepr(doc) -} - -/** * Signs and the encrypts the data to send via EBICS. * * @param cfg configuration handle. @@ -527,6 +509,7 @@ suspend fun doEbicsUpload( orderService: Ebics3Request.OrderDetails.Service, payload: ByteArray, ): EbicsResponseContent { + // TODO use a lambda and pass the order detail there for atomicity ? val preparedPayload = prepareUploadPayload(cfg, clientKeys, bankKeys, payload, isEbics3 = true) val initXml = createEbics3RequestForUploadInitialization( cfg, |