diff options
author | Antoine A <> | 2024-03-11 17:14:24 +0100 |
---|---|---|
committer | Antoine A <> | 2024-03-11 17:14:24 +0100 |
commit | 0d62875dd2287857c5da172dcb3301062880810a (patch) | |
tree | 6880751fb475a9f0db8dcedbf8ef8e78a299f729 | |
parent | 861389ea98224e86f28fdf06570a260c3ae12f90 (diff) | |
download | libeufin-0d62875dd2287857c5da172dcb3301062880810a.tar.gz libeufin-0d62875dd2287857c5da172dcb3301062880810a.tar.bz2 libeufin-0d62875dd2287857c5da172dcb3301062880810a.zip |
Support both 2.5 and 3 EBICS version for download
-rw-r--r-- | nexus/src/main/kotlin/tech/libeufin/nexus/EbicsFetch.kt | 5 | ||||
-rw-r--r-- | nexus/src/main/kotlin/tech/libeufin/nexus/EbicsSetup.kt | 2 | ||||
-rw-r--r-- | nexus/src/main/kotlin/tech/libeufin/nexus/EbicsSubmit.kt | 9 | ||||
-rw-r--r-- | nexus/src/main/kotlin/tech/libeufin/nexus/XMLUtil.kt | 10 | ||||
-rw-r--r-- | nexus/src/main/kotlin/tech/libeufin/nexus/ebics/EbicsBTS.kt (renamed from nexus/src/main/kotlin/tech/libeufin/nexus/ebics/Ebics3.kt) | 146 | ||||
-rw-r--r-- | nexus/src/main/kotlin/tech/libeufin/nexus/ebics/EbicsCommon.kt | 90 | ||||
-rw-r--r-- | nexus/src/main/kotlin/tech/libeufin/nexus/ebics/EbicsDialect.kt | 49 | ||||
-rw-r--r-- | nexus/src/main/kotlin/tech/libeufin/nexus/ebics/EbicsKeyMng.kt (renamed from nexus/src/main/kotlin/tech/libeufin/nexus/ebics/Ebics2.kt) | 8 | ||||
-rw-r--r-- | nexus/src/main/kotlin/tech/libeufin/nexus/ebics/EbicsOrder.kt | 59 |
9 files changed, 160 insertions, 218 deletions
diff --git a/nexus/src/main/kotlin/tech/libeufin/nexus/EbicsFetch.kt b/nexus/src/main/kotlin/tech/libeufin/nexus/EbicsFetch.kt index c74ea2f1..ca7b9116 100644 --- a/nexus/src/main/kotlin/tech/libeufin/nexus/EbicsFetch.kt +++ b/nexus/src/main/kotlin/tech/libeufin/nexus/EbicsFetch.kt @@ -285,14 +285,13 @@ private suspend fun fetchDocuments( } // downloading the content val doc = doc.doc() - val (orderType, service) = downloadDocService(doc) + val order = downloadDocService(doc, doc == SupportedDocument.PAIN_002_LOGS) ebicsDownload( ctx.httpClient, ctx.cfg, ctx.clientKeys, ctx.bankKeys, - orderType, - service, + order, lastExecutionTime, null ) { stream -> diff --git a/nexus/src/main/kotlin/tech/libeufin/nexus/EbicsSetup.kt b/nexus/src/main/kotlin/tech/libeufin/nexus/EbicsSetup.kt index 230b2cc9..b0cbc299 100644 --- a/nexus/src/main/kotlin/tech/libeufin/nexus/EbicsSetup.kt +++ b/nexus/src/main/kotlin/tech/libeufin/nexus/EbicsSetup.kt @@ -116,7 +116,7 @@ suspend fun doKeysRequestAndUpdateState( KeysOrderType.HIA -> impl.HIA() KeysOrderType.HPB -> impl.HPB() } - val xml = client.postToBank(cfg.hostBaseUrl, req) + val xml = client.postToBank(cfg.hostBaseUrl, req, "$orderType") val resp = Ebics3KeyMng.parseResponse(xml, privs.encryption_private_key) when (orderType) { diff --git a/nexus/src/main/kotlin/tech/libeufin/nexus/EbicsSubmit.kt b/nexus/src/main/kotlin/tech/libeufin/nexus/EbicsSubmit.kt index ea20967e..82c1a459 100644 --- a/nexus/src/main/kotlin/tech/libeufin/nexus/EbicsSubmit.kt +++ b/nexus/src/main/kotlin/tech/libeufin/nexus/EbicsSubmit.kt @@ -25,7 +25,7 @@ import com.github.ajalt.clikt.parameters.options.* import io.ktor.client.* import kotlinx.coroutines.* import tech.libeufin.common.* -import tech.libeufin.nexus.ebics.submitPain001 +import tech.libeufin.nexus.ebics.* import java.time.* import java.util.* @@ -85,12 +85,13 @@ private suspend fun submitInitiatedPayment( wireTransferSubject = payment.wireTransferSubject ) ctx.fileLogger.logSubmit(xml) - return submitPain001( - xml, + return doEbicsUpload( + ctx.httpClient, ctx.cfg, ctx.clientPrivateKeysFile, ctx.bankPublicKeysFile, - ctx.httpClient + uploadPaymentService(), + xml ) } diff --git a/nexus/src/main/kotlin/tech/libeufin/nexus/XMLUtil.kt b/nexus/src/main/kotlin/tech/libeufin/nexus/XMLUtil.kt index bbae68ae..2893f367 100644 --- a/nexus/src/main/kotlin/tech/libeufin/nexus/XMLUtil.kt +++ b/nexus/src/main/kotlin/tech/libeufin/nexus/XMLUtil.kt @@ -113,11 +113,10 @@ object XMLUtil { fun signEbicsDocument( doc: Document, signingPriv: PrivateKey, - withEbics3: Boolean = false + schema: String ) { - val ns = if (withEbics3) "urn:org:ebics:H005" else "urn:org:ebics:H004" val authSigNode = XPathFactory.newInstance().newXPath() - .evaluate("/*[1]/$ns:AuthSignature", doc, XPathConstants.NODE) + .evaluate("/*[1]/urn:org:ebics:$schema:AuthSignature", doc, XPathConstants.NODE) if (authSigNode !is Node) throw java.lang.Exception("no AuthSignature") val fac = XMLSignatureFactory.getInstance("DOM") @@ -150,12 +149,11 @@ object XMLUtil { fun verifyEbicsDocument( doc: Document, signingPub: PublicKey, - withEbics3: Boolean = false + schema: String ): Boolean { val doc2: Document = doc.cloneNode(true) as Document - val ns = if (withEbics3) "urn:org:ebics:H005" else "urn:org:ebics:H004" val authSigNode = XPathFactory.newInstance().newXPath() - .evaluate("/*[1]/$ns:AuthSignature", doc2, XPathConstants.NODE) + .evaluate("/*[1]/urn:org:ebics:$schema:AuthSignature", doc2, XPathConstants.NODE) if (authSigNode !is Node) throw java.lang.Exception("no AuthSignature") val sigEl = doc2.createElementNS("http://www.w3.org/2000/09/xmldsig#", "ds:Signature") diff --git a/nexus/src/main/kotlin/tech/libeufin/nexus/ebics/Ebics3.kt b/nexus/src/main/kotlin/tech/libeufin/nexus/ebics/EbicsBTS.kt index 5acba13b..356d4b96 100644 --- a/nexus/src/main/kotlin/tech/libeufin/nexus/ebics/Ebics3.kt +++ b/nexus/src/main/kotlin/tech/libeufin/nexus/ebics/EbicsBTS.kt @@ -36,59 +36,16 @@ import java.security.interfaces.* fun Instant.xmlDate(): String = DateTimeFormatter.ISO_DATE.withZone(ZoneId.of("UTC")).format(this) fun Instant.xmlDateTime(): String = DateTimeFormatter.ISO_OFFSET_DATE_TIME.withZone(ZoneId.of("UTC")).format(this) -// TODO WIP -fun iniRequest( - cfg: EbicsSetupConfig, - clientKeys: ClientPrivateKeysFile -): ByteArray { - val temp = XmlBuilder.toBytes("ns2:SignaturePubKeyOrderData") { - attr("xmlns:ds", "http://www.w3.org/2000/09/xmldsig#") - attr("xmlns:ns2", "http://www.ebics.org/S001") - el("ns2:SignaturePubKeyInfo") { - el("ns2:PubKeyValue") { - el("ds:RSAKeyValue") { - el("ds:Modulus", clientKeys.signature_private_key.modulus.encodeBase64()) - el("ds:Exponent", clientKeys.signature_private_key.publicExponent.encodeBase64()) - } - } - el("ns2:SignatureVersion", "A006") - } - el("ns2:PartnerID", cfg.ebicsPartnerId) - el("ns2:UserID", cfg.ebicsUserId) - } - // TODO in ebics:H005 we MUST use x509 certificates ... - println(temp) - val inner = temp.inputStream().deflate().encodeBase64() - val doc = XmlBuilder.toDom("ebicsUnsecuredRequest", "urn:org:ebics:H005") { - attr("http://www.w3.org/2000/xmlns/", "xmlns", "urn:org:ebics:H005") - attr("http://www.w3.org/2000/xmlns/", "xmlns:ds", "http://www.w3.org/2000/09/xmldsig#") - attr("Version", "H005") - attr("Revision", "1") - el("header") { - attr("authenticate", "true") - el("static") { - el("HostID", cfg.ebicsHostId) - el("PartnerID", cfg.ebicsPartnerId) - el("UserID", cfg.ebicsUserId) - el("OrderDetails/AdminOrderType", "INI") - el("SecurityMedium", "0200") - } - el("mutable") - } - el("body/DataTransfer/OrderData", inner) - } - return XMLUtil.convertDomToBytes(doc) -} - -/** EBICS 3 protocol for business transactions */ -class Ebics3BTS( - private val cfg: EbicsSetupConfig, - private val bankKeys: BankPublicKeysFile, - private val clientKeys: ClientPrivateKeysFile +/** EBICS protocol for business transactions */ +class EbicsBTS( + val cfg: EbicsSetupConfig, + val bankKeys: BankPublicKeysFile, + val clientKeys: ClientPrivateKeysFile, + val order: EbicsOrder ) { /* ----- Download ----- */ - fun downloadInitialization(orderType: String, service: Ebics3Service?, startDate: Instant?, endDate: Instant?): ByteArray { + fun downloadInitialization(startDate: Instant?, endDate: Instant?): ByteArray { val nonce = getNonce(128) return signedRequest { el("header") { @@ -102,28 +59,42 @@ class Ebics3BTS( // SystemID // Product el("OrderDetails") { - el("AdminOrderType", orderType) - if (orderType == "BTD") { - el("BTDOrderParams") { - if (service != null) { - el("Service") { - el("ServiceName", service.name) - el("Scope", service.scope) - if (service.container != null) { - el("Container") { - attr("containerType", service.container) - } - } - el("MsgName") { - attr("version", service.messageVersion) - text(service.messageName) + when (order) { + is EbicsOrder.V2_5 -> { + el("OrderType", order.type) + el("OrderAttribute", order.attribute) + el("StandardOrderParams") { + if (startDate != null) { + el("DateRange") { + el("Start", startDate.xmlDate()) + el("End", (endDate ?: Instant.now()).xmlDate()) } } } - if (startDate != null) { - el("DateRange") { - el("Start", startDate.xmlDate()) - el("End", (endDate ?: Instant.now()).xmlDate()) + } + is EbicsOrder.V3 -> { + el("AdminOrderType", order.type) + if (order.type == "BTD") { + el("BTDOrderParams") { + el("Service") { + el("ServiceName", order.name!!) + el("Scope", order.scope!!) + if (order.container != null) { + el("Container") { + attr("containerType", order.container) + } + } + el("MsgName") { + attr("version", order.messageVersion!!) + text(order.messageName!!) + } + } + if (startDate != null) { + el("DateRange") { + el("Start", startDate.xmlDate()) + el("End", (endDate ?: Instant.now()).xmlDate()) + } + } } } } @@ -187,7 +158,7 @@ class Ebics3BTS( /* ----- Upload ----- */ - fun uploadInitialization(service: Ebics3Service, preparedUploadData: PreparedUploadData): ByteArray { + fun uploadInitialization(preparedUploadData: PreparedUploadData): ByteArray { val nonce = getNonce(128) return signedRequest { el("header") { @@ -201,17 +172,24 @@ class Ebics3BTS( // SystemID // Product el("OrderDetails") { - el("AdminOrderType", "BTU") - el("BTUOrderParams") { - el("Service") { - el("ServiceName", service.name) - el("Scope", service.scope) - el("MsgName") { - attr("version", service.messageVersion) - text(service.messageName) + when (order) { + is EbicsOrder.V2_5 -> { + // TODO + } + is EbicsOrder.V3 -> { + el("AdminOrderType", order.type) + el("BTUOrderParams") { + el("Service") { + el("ServiceName", order.name!!) + el("Scope", order.scope!!) + el("MsgName") { + attr("version", order.messageVersion!!) + text(order.messageName!!) + } + } + el("SignatureFlag", "true") } } - el("SignatureFlag", "true") } } bankDigest() @@ -274,19 +252,19 @@ class Ebics3BTS( /* ----- Helpers ----- */ - /** Generate a signed H005 ebicsRequest */ + /** Generate a signed ebicsRequest */ private fun signedRequest(lambda: XmlBuilder.() -> Unit): ByteArray { - val doc = XmlBuilder.toDom("ebicsRequest", "urn:org:ebics:H005") { - attr("http://www.w3.org/2000/xmlns/", "xmlns", "urn:org:ebics:H005") + val doc = XmlBuilder.toDom("ebicsRequest", "urn:org:ebics:${order.schema}") { + attr("http://www.w3.org/2000/xmlns/", "xmlns", "urn:org:ebics:${order.schema}") attr("http://www.w3.org/2000/xmlns/", "xmlns:ds", "http://www.w3.org/2000/09/xmldsig#") - attr("Version", "H005") + attr("Version", order.schema) attr("Revision", "1") lambda() } XMLUtil.signEbicsDocument( doc, clientKeys.authentication_private_key, - withEbics3 = true + order.schema ) return XMLUtil.convertDomToBytes(doc) } 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 69e6da19..74c1dd32 100644 --- a/nexus/src/main/kotlin/tech/libeufin/nexus/ebics/EbicsCommon.kt +++ b/nexus/src/main/kotlin/tech/libeufin/nexus/ebics/EbicsCommon.kt @@ -109,45 +109,45 @@ sealed class EbicsError(msg: String, cause: Throwable? = null): Exception(msg, c * @param msg EBICS message as raw bytes. * @return the raw bank response. */ -suspend fun HttpClient.postToBank(bankUrl: String, msg: ByteArray): Document { +suspend fun HttpClient.postToBank(bankUrl: String, msg: ByteArray, phase: String): Document { val res = try { post(urlString = bankUrl) { contentType(ContentType.Text.Xml) setBody(msg) } } catch (e: Exception) { - throw EbicsError.Transport("failed to contact bank", e) + throw EbicsError.Transport("$phase: failed to contact bank", e) } if (res.status != HttpStatusCode.OK) { - throw EbicsError.Transport("bank HTTP error: ${res.status}") + throw EbicsError.Transport("$phase: bank HTTP error: ${res.status}") } try { return XMLUtil.parseIntoDom(res.bodyAsChannel().toInputStream()) } catch (e: SAXException) { - throw EbicsError.Protocol("invalid XML bank reponse", e) + throw EbicsError.Protocol("$phase: invalid XML bank reponse", e) } catch (e: Exception) { - throw EbicsError.Transport("failed read bank response", e) + throw EbicsError.Transport("$phase: failed read bank response", e) } } -suspend fun postBTS( + +suspend fun EbicsBTS.postBTS( client: HttpClient, - cfg: EbicsSetupConfig, - bankKeys: BankPublicKeysFile, - xmlReq: ByteArray + xmlReq: ByteArray, + phase: String, ): EbicsResponse<BTSResponse> { - val doc = client.postToBank(cfg.hostBaseUrl, xmlReq) + val doc = client.postToBank(cfg.hostBaseUrl, xmlReq, phase) if (!XMLUtil.verifyEbicsDocument( doc, bankKeys.bank_authentication_public_key, - true + order.schema )) { - throw EbicsError.Protocol("bank signature did not verify") + throw EbicsError.Protocol("$phase: bank signature did not verify") } try { - return Ebics3BTS.parseResponse(doc) + return EbicsBTS.parseResponse(doc) } catch (e: Exception) { - throw EbicsError.Protocol("invalid ebics response", e) + throw EbicsError.Protocol("$phase: invalid ebics response", e) } } @@ -170,13 +170,12 @@ suspend fun ebicsDownload( cfg: EbicsSetupConfig, clientKeys: ClientPrivateKeysFile, bankKeys: BankPublicKeysFile, - orderType: String, - service: Ebics3Service?, + order: EbicsOrder, startDate: Instant?, endDate: Instant?, processing: (InputStream) -> Unit, ) = coroutineScope { - val impl = Ebics3BTS(cfg, bankKeys, clientKeys) + val impl = EbicsBTS(cfg, bankKeys, clientKeys, order) val parentScope = this // We need to run the logic in a non-cancelable context because we need to send @@ -185,8 +184,8 @@ suspend fun ebicsDownload( // TODO find a way to cancel the pending transaction ? withContext(NonCancellable) { // Init phase - val initReq = impl.downloadInitialization(orderType, service, startDate, endDate) - val initResp = postBTS(client, cfg, bankKeys, initReq) + val initReq = impl.downloadInitialization(startDate, endDate) + val initResp = impl.postBTS(client, initReq, "Download init phase") if (initResp.bankCode == EbicsReturnCode.EBICS_NO_DOWNLOAD_DATA_AVAILABLE) { logger.debug("Download content is empty") return@withContext @@ -210,7 +209,7 @@ suspend fun ebicsDownload( /** Send download receipt */ suspend fun receipt(success: Boolean) { val xml = impl.downloadReceipt(tId, success) - postBTS(client, cfg, bankKeys, xml).okOrFail("Download receipt phase") + impl.postBTS(client, xml, "Download receipt phase").okOrFail("Download receipt phase") } /** Throw if parent scope have been canceled */ suspend fun checkCancellation() { @@ -227,7 +226,7 @@ suspend fun ebicsDownload( for (x in 2 .. howManySegments) { checkCancellation() val transReq = impl.downloadTransfer(x, howManySegments, tId) - val transResp = postBTS(client, cfg, bankKeys, transReq).okOrFail("Download transfer phase") + val transResp = impl.postBTS(client, transReq, "Download transfer phase").okOrFail("Download transfer phase") val chunk = requireNotNull(transResp.payloadChunk) { "Download transfer phase: missing encrypted chunk" } @@ -329,23 +328,23 @@ suspend fun doEbicsUpload( cfg: EbicsSetupConfig, clientKeys: ClientPrivateKeysFile, bankKeys: BankPublicKeysFile, - service: Ebics3Service, + order: EbicsOrder, payload: ByteArray, ): String = withContext(NonCancellable) { - val impl = Ebics3BTS(cfg, bankKeys, clientKeys) + val impl = EbicsBTS(cfg, bankKeys, clientKeys, order) // TODO use a lambda and pass the order detail there for atomicity ? val preparedPayload = prepareUploadPayload(cfg, clientKeys, bankKeys, payload) // Init phase - val initXml = impl.uploadInitialization(service, preparedPayload) - val initResp = postBTS(client, cfg, bankKeys, initXml).okOrFail("Upload init phase") + val initXml = impl.uploadInitialization(preparedPayload) + val initResp = impl.postBTS(client, initXml, "Upload init phase").okOrFail("Upload init phase") val tId = requireNotNull(initResp.transactionID) { "Upload init phase: missing transaction ID" } // Transfer phase val transferXml = impl.uploadTransfer(tId, preparedPayload) - val transferResp = postBTS(client, cfg, bankKeys, transferXml).okOrFail("Upload transfer phase") + val transferResp = impl.postBTS(client, transferXml, "Upload transfer phase").okOrFail("Upload transfer phase") val orderId = requireNotNull(transferResp.orderID) { "Upload transfer phase: missing order ID" } @@ -374,45 +373,6 @@ class DataEncryptionInfo( val bankPubDigest: ByteArray ) -/** - * Collects all the steps to prepare the submission of a pain.001 - * document to the bank, and finally send it. Indirectly throws - * [EbicsSideException] or [EbicsUploadException]. The first means - * that the bank sent an invalid response or signature, the second - * that a proper EBICS or business error took place. The caller must - * catch those exceptions and decide the retry policy. - * - * @param pain001xml pain.001 document in XML. The caller should - * ensure its validity. - * @param cfg configuration handle. - * @param clientKeys client private keys. - * @param bankkeys bank public keys. - * @param httpClient HTTP client to connect to the bank. - */ -suspend fun submitPain001( - pain001xml: ByteArray, - cfg: EbicsSetupConfig, - clientKeys: ClientPrivateKeysFile, - bankkeys: BankPublicKeysFile, - httpClient: HttpClient -): String { - val service = Ebics3Service( - name = "MCT", - scope = "CH", - messageName = "pain.001", - messageVersion = "09", - container = null - ) - return doEbicsUpload( - httpClient, - cfg, - clientKeys, - bankkeys, - service, - pain001xml, - ) -} - class EbicsResponse<T>( val technicalCode: EbicsReturnCode, val bankCode: EbicsReturnCode, diff --git a/nexus/src/main/kotlin/tech/libeufin/nexus/ebics/EbicsDialect.kt b/nexus/src/main/kotlin/tech/libeufin/nexus/ebics/EbicsDialect.kt deleted file mode 100644 index 5d672de0..00000000 --- a/nexus/src/main/kotlin/tech/libeufin/nexus/ebics/EbicsDialect.kt +++ /dev/null @@ -1,49 +0,0 @@ -/* - * This file is part of LibEuFin. - * Copyright (C) 2024 Taler Systems S.A. - - * LibEuFin is free software; you can redistribute it and/or modify - * it under the terms of the GNU Affero General Public License as - * published by the Free Software Foundation; either version 3, or - * (at your option) any later version. - - * LibEuFin is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY - * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General - * Public License for more details. - - * You should have received a copy of the GNU Affero General Public - * License along with LibEuFin; see the file COPYING. If not, see - * <http://www.gnu.org/licenses/> - */ -package tech.libeufin.nexus.ebics - -// We will support more dialect in the future - -data class Ebics3Service( - val name: String, - val scope: String, - val messageName: String, - val messageVersion: String, - val container: String? -) - -fun downloadDocService(doc: SupportedDocument): Pair<String, Ebics3Service?> { - return when (doc) { - SupportedDocument.PAIN_002 -> Pair("BTD", Ebics3Service("PSR", "CH", "pain.002", "10", "ZIP")) - SupportedDocument.CAMT_052 -> Pair("BTD", Ebics3Service("STM", "CH", "camt.052", "08", "ZIP")) - SupportedDocument.CAMT_053 -> Pair("BTD", Ebics3Service("EOP", "CH", "camt.053", "08", "ZIP")) - SupportedDocument.CAMT_054 -> Pair("BTD", Ebics3Service("REP", "CH", "camt.054", "08", "ZIP")) - SupportedDocument.PAIN_002_LOGS -> Pair("HAC", null) - } -} - -fun uploadPaymentService(): Ebics3Service { - return Ebics3Service( - name = "MCT", - scope = "CH", - messageName = "pain.001", - messageVersion = "09", - container = null - ) -} diff --git a/nexus/src/main/kotlin/tech/libeufin/nexus/ebics/Ebics2.kt b/nexus/src/main/kotlin/tech/libeufin/nexus/ebics/EbicsKeyMng.kt index a7c2ba50..1847beec 100644 --- a/nexus/src/main/kotlin/tech/libeufin/nexus/ebics/Ebics2.kt +++ b/nexus/src/main/kotlin/tech/libeufin/nexus/ebics/EbicsKeyMng.kt @@ -17,10 +17,6 @@ * <http://www.gnu.org/licenses/> */ -/** - * This file contains helpers to construct EBICS 2.x requests. - */ - package tech.libeufin.nexus.ebics import org.w3c.dom.Document @@ -37,7 +33,7 @@ import java.util.* import javax.xml.datatype.DatatypeFactory import java.security.interfaces.* -/** Ebics 3 protocol for */ +/** EBICS protocol for key management */ class Ebics3KeyMng( private val cfg: EbicsSetupConfig, private val clientKeys: ClientPrivateKeysFile @@ -134,7 +130,7 @@ class Ebics3KeyMng( el("AuthSignature") el("body") } - XMLUtil.signEbicsDocument(doc, clientKeys.authentication_private_key) + XMLUtil.signEbicsDocument(doc, clientKeys.authentication_private_key, "H004") return XMLUtil.convertDomToBytes(doc) } diff --git a/nexus/src/main/kotlin/tech/libeufin/nexus/ebics/EbicsOrder.kt b/nexus/src/main/kotlin/tech/libeufin/nexus/ebics/EbicsOrder.kt new file mode 100644 index 00000000..3c73fff0 --- /dev/null +++ b/nexus/src/main/kotlin/tech/libeufin/nexus/ebics/EbicsOrder.kt @@ -0,0 +1,59 @@ +/* + * This file is part of LibEuFin. + * Copyright (C) 2024 Taler Systems S.A. + + * LibEuFin is free software; you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as + * published by the Free Software Foundation; either version 3, or + * (at your option) any later version. + + * LibEuFin is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY + * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General + * Public License for more details. + + * You should have received a copy of the GNU Affero General Public + * License along with LibEuFin; see the file COPYING. If not, see + * <http://www.gnu.org/licenses/> + */ +package tech.libeufin.nexus.ebics + +// We will support more dialect in the future + +sealed class EbicsOrder(val schema: String) { + data class V2_5( + val type: String, + val attribute: String + ): EbicsOrder("H004") + data class V3( + val type: String, + val name: String? = null, + val scope: String? = null, + val messageName: String? = null, + val messageVersion: String? = null, + val container: String? = null, + ): EbicsOrder("H005") +} + +fun downloadDocService(doc: SupportedDocument, ebics2: Boolean): EbicsOrder { + return if (ebics2) { + when (doc) { + SupportedDocument.PAIN_002 -> EbicsOrder.V2_5("Z01", "DZHNN") + SupportedDocument.CAMT_052 -> EbicsOrder.V2_5("Z52", "DZHNN") + SupportedDocument.CAMT_053 -> EbicsOrder.V2_5("Z53", "DZHNN") + SupportedDocument.CAMT_054 -> EbicsOrder.V2_5("Z54", "DZHNN") + SupportedDocument.PAIN_002_LOGS -> EbicsOrder.V2_5("HAC", "DZHNN") + } + } else { + when (doc) { + SupportedDocument.PAIN_002 -> EbicsOrder.V3("BTD", "PSR", "CH", "pain.002", "10", "ZIP") + SupportedDocument.CAMT_052 -> EbicsOrder.V3("BTD", "STM", "CH", "camt.052", "08", "ZIP") + SupportedDocument.CAMT_053 -> EbicsOrder.V3("BTD", "EOP", "CH", "camt.053", "08", "ZIP") + SupportedDocument.CAMT_054 -> EbicsOrder.V3("BTD", "REP", "CH", "camt.054", "08", "ZIP") + SupportedDocument.PAIN_002_LOGS -> EbicsOrder.V3("HAC") + } + } +} + +fun uploadPaymentService(): EbicsOrder = + EbicsOrder.V3("BTU", "MCT", "CH", "pain.001", "09") |