From 448776c1274ed4dd554bb9dad6e6cc330d35743f Mon Sep 17 00:00:00 2001 From: Merlin Scholz Date: Wed, 13 May 2026 20:15:33 +0200 Subject: INI works --- certificate.go | 18 ++++++++++-- certificate_test.go | 2 +- config.go | 1 + config_test.go | 1 + go.mod | 4 +++ go.sum | 4 +++ order.go | 84 +++++++++++++++++++++++++++++++++++++++++++++++++++++ order_test.go | 63 ++++++++++++++++++++++++++++++++++++++++ 8 files changed, 174 insertions(+), 3 deletions(-) create mode 100644 config.go create mode 100644 config_test.go create mode 100644 go.sum create mode 100644 order.go create mode 100644 order_test.go diff --git a/certificate.go b/certificate.go index 72a823a..17de0a1 100644 --- a/certificate.go +++ b/certificate.go @@ -1,4 +1,4 @@ -package main +package libebics import ( "crypto/rand" @@ -21,6 +21,21 @@ const ( E002 ) +func (t EbicsCertificateType) String() string { + switch t { + case A005: + return "A005" + case A006: + return "A006" + case X002: + return "X002" + case E002: + return "E002" + default: + panic("invalid EbicsCertificateType") + } +} + type EbicsCertificate struct { x509Certificate []byte ebicsCertificateType EbicsCertificateType @@ -109,7 +124,6 @@ func ReadCertificateFromFile(path string, ebicsCertificateType EbicsCertificateT if cert.KeyUsage != keyUsage { return nil, fmt.Errorf("expected KeyUsage %s does not match KeyUsage in loaded Certificate (%s)", keyUsage, cert.KeyUsage) } - return &EbicsCertificate{ x509Certificate: cert.Raw, ebicsCertificateType: ebicsCertificateType, diff --git a/certificate_test.go b/certificate_test.go index 3c9dcc5..dd0297b 100644 --- a/certificate_test.go +++ b/certificate_test.go @@ -1,4 +1,4 @@ -package main +package libebics import ( "bytes" diff --git a/config.go b/config.go new file mode 100644 index 0000000..18919be --- /dev/null +++ b/config.go @@ -0,0 +1 @@ +package libebics diff --git a/config_test.go b/config_test.go new file mode 100644 index 0000000..18919be --- /dev/null +++ b/config_test.go @@ -0,0 +1 @@ +package libebics diff --git a/go.mod b/go.mod index b9692b1..d05e5cf 100644 --- a/go.mod +++ b/go.mod @@ -1,3 +1,7 @@ module go.scholz.ruhr/libebics go 1.26.2 + +require github.com/beevik/etree v1.6.0 + +require github.com/terminalstatic/go-xsd-validate v0.1.6 // indirect diff --git a/go.sum b/go.sum new file mode 100644 index 0000000..a1c3c90 --- /dev/null +++ b/go.sum @@ -0,0 +1,4 @@ +github.com/beevik/etree v1.6.0 h1:u8Kwy8pp9D9XeITj2Z0XtA5qqZEmtJtuXZRQi+j03eE= +github.com/beevik/etree v1.6.0/go.mod h1:bh4zJxiIr62SOf9pRzN7UUYaEDa9HEKafK25+sLc0Gc= +github.com/terminalstatic/go-xsd-validate v0.1.6 h1:TenYeQ3eY631qNi1/cTmLH/s2slHPRKTTHT+XSHkepo= +github.com/terminalstatic/go-xsd-validate v0.1.6/go.mod h1:18lsvYFofBflqCrvo1umpABZ99+GneNTw2kEEc8UPJw= diff --git a/order.go b/order.go new file mode 100644 index 0000000..bf90078 --- /dev/null +++ b/order.go @@ -0,0 +1,84 @@ +package libebics + +import ( + "bytes" + "compress/zlib" + "encoding/base64" + "fmt" + + "github.com/beevik/etree" +) + +func GenerateIniRequest(signatureCertificate EbicsCertificate) (string, error) { + if signatureCertificate.ebicsCertificateType != A005 && + signatureCertificate.ebicsCertificateType != A006 { + return "", fmt.Errorf("signature certificate has invalid certificate type %s", signatureCertificate.ebicsCertificateType.String()) + } + var zlibWriterBuffer bytes.Buffer + zlibWriter := zlib.NewWriter(&zlibWriterBuffer) + + var orderdata *etree.Element + + ini := etree.NewDocument() + ini.Indent(2) // Not technically efficient but nice for debugging purposes + ini.CreateProcInst("xml", `version="1.0" encoding="UTF-8"`) + ini.CreateChild("ebicsUnsecuredRequest", func(e *etree.Element) { + e.CreateAttr("xmlns", "urn:org:ebics:H005") + e.CreateAttr("Version", "H005") + e.CreateAttr("Revision", "1") + + e.CreateChild("header", func(e *etree.Element) { + e.CreateAttr("authenticate", "true") + e.CreateChild("static", func(e *etree.Element) { + e.CreateElement("HostID").CreateText("MULTIVIA") + e.CreateElement("PartnerID").CreateText("MV008078") + e.CreateElement("UserID").CreateText("SCHOLZ01") + e.CreateChild("Product", func(e *etree.Element) { + e.CreateAttr("Language", "en") + e.CreateText("libebics") + }) + e.CreateElement("OrderDetails").CreateElement("AdminOrderType").CreateText("INI") + e.CreateElement("SecurityMedium").CreateText("0000") + }) + e.CreateElement("mutable") + }) + + e.CreateChild("body", func(e *etree.Element) { + orderdata = e.CreateElement("DataTransfer").CreateElement("OrderData") + }) + }) + + orderdata_content := etree.NewDocument() + orderdata_content.Indent(2) // Not technically efficient but nice for debugging purposes + orderdata_content.CreateChild("esig:SignaturePubKeyOrderData", func(e *etree.Element) { + e.CreateAttr("xmlns:esig", "http://www.ebics.org/S002") + e.CreateAttr("xmlns:ds", "http://www.w3.org/2000/09/xmldsig#") + e.CreateChild("esig:SignaturePubKeyInfo", func(e *etree.Element) { + e.CreateChild("ds:X509Data", func(e *etree.Element) { + e.CreateElement("ds:X509Certificate").CreateText( + base64.StdEncoding.EncodeToString( + signatureCertificate.x509Certificate, + ), + ) + }) + e.CreateElement("esig:SignatureVersion").CreateText(signatureCertificate.ebicsCertificateType.String()) + }) + e.CreateElement("esig:PartnerID").CreateText("MV008078") + e.CreateElement("esig:UserID").CreateText("SCHOLZ01") + }) + + orderdata_bytes, err := orderdata_content.WriteToBytes() + if err != nil { + panic(err.Error()) + } + zlibWriter.Write(orderdata_bytes) + zlibWriter.Close() + + orderdata.CreateText( + base64.StdEncoding.EncodeToString( + zlibWriterBuffer.Bytes(), + ), + ) + + return ini.WriteToString() +} diff --git a/order_test.go b/order_test.go new file mode 100644 index 0000000..605042a --- /dev/null +++ b/order_test.go @@ -0,0 +1,63 @@ +package libebics + +import ( + "io" + "net/http" + "path/filepath" + "strings" + "testing" +) + +func TestSendIniRequest(t *testing.T) { + signatureCertificate, err := ReadCertificateFromFile(filepath.Join("certs", "signature_cert.pem"), A005) + if err != nil { + t.Error(err.Error()) + } + + ini, err := GenerateIniRequest(*signatureCertificate) + if err != nil { + t.Error(err.Error()) + } + + t.Log(ini) + + resp, err := http.Post( + "https://ebics-test.multivia-suite.de/MVB_ENT/ebicsweb", + "text/xml; charset=UTF-8", + strings.NewReader(ini), + ) + if err != nil { + t.Error(err.Error()) + } + defer resp.Body.Close() + + body, err := io.ReadAll(resp.Body) + t.Log(string(body)) +} + +func TestSendHiaRequest(t *testing.T) { + signatureCertificate, err := ReadCertificateFromFile(filepath.Join("certs", "signature_cert.pem"), A005) + if err != nil { + t.Error(err.Error()) + } + + ini, err := GenerateIniRequest(*signatureCertificate) + if err != nil { + t.Error(err.Error()) + } + + t.Log(ini) + + resp, err := http.Post( + "https://ebics-test.multivia-suite.de/MVB_ENT/ebicsweb", + "text/xml; charset=UTF-8", + strings.NewReader(ini), + ) + if err != nil { + t.Error(err.Error()) + } + defer resp.Body.Close() + + body, err := io.ReadAll(resp.Body) + t.Log(string(body)) +} -- cgit