From cd8a7ed329ee980c60acc26145efb2a5b941dd81 Mon Sep 17 00:00:00 2001 From: Philipp Kern Date: Thu, 19 Sep 2019 09:06:18 +0200 Subject: [PATCH] Make it possible to send the productName With PSD2 banks now require registration of programs (rather than libraries) with "Die Deutsche Kreditwirtschaft" on https://www.hbci-zka.de. You are given a key that needs to be passed in the product name field for access to be granted. Everyone can apply for this key for their program. --- client/client.go | 16 ++++++++++------ dialog/dialog.go | 12 +++++++++--- dialog/pin_tan_dialog.go | 14 +++++++++----- dialog/rdh_dialog.go | 4 ++-- segment/dialog.go | 20 ++++++++++++++++---- 5 files changed, 46 insertions(+), 20 deletions(-) diff --git a/client/client.go b/client/client.go index 6cf71bc..658935a 100644 --- a/client/client.go +++ b/client/client.go @@ -23,7 +23,9 @@ type Config struct { URL string `json:"url"` HBCIVersion int `json:"hbci_version"` Transport transport.Transport - EnableDebugLogging bool `json:"enable_debug_logging"` + ProductName string `json:"product_name"` + ProductVersion string `json:"product_version"` + EnableDebugLogging bool `json:"enable_debug_logging"` } func (c Config) hbciVersion() (segment.HBCIVersion, error) { @@ -70,11 +72,13 @@ func New(config Config) (*Client, error) { hbciVersion = version } dcfg := dialog.Config{ - BankID: bankID, - HBCIURL: url, - UserID: config.AccountID, - HBCIVersion: hbciVersion, - Transport: config.Transport, + BankID: bankID, + HBCIURL: url, + UserID: config.AccountID, + HBCIVersion: hbciVersion, + ProductName: config.ProductName, + ProductVersion: config.ProductVersion, + Transport: config.Transport, } d := dialog.NewPinTanDialog(dcfg) diff --git a/dialog/dialog.go b/dialog/dialog.go index 347ca9e..241b276 100644 --- a/dialog/dialog.go +++ b/dialog/dialog.go @@ -38,6 +38,8 @@ func newDialog( hbciURL string, userID string, hbciVersion segment.HBCIVersion, + productName string, + productVersion string, signatureProvider message.SignatureProvider, cryptoProvider message.CryptoProvider, ) *dialog { @@ -53,6 +55,8 @@ func newDialog( cryptoProvider: cryptoProvider, dialogID: initialDialogID, hbciVersion: hbciVersion, + productName: productName, + productVersion: productVersion, } } @@ -73,6 +77,8 @@ type dialog struct { cryptoProvider message.CryptoProvider BankParameterData BankParameterData hbciVersion segment.HBCIVersion + productName string + productVersion string supportedSegments []segment.VersionedSegment } @@ -152,7 +158,7 @@ func (d *dialog) SyncClientSystemID() (string, error) { syncMessage := message.NewSynchronisationMessage(d.hbciVersion) syncMessage.Identification = segment.NewIdentificationSegment(d.BankID, d.clientID, initialClientSystemID, true) syncMessage.ProcessingPreparation = segment.NewProcessingPreparationSegmentV3( - initialBankParameterDataVersion, initialUserParameterDataVersion, domain.German, + initialBankParameterDataVersion, initialUserParameterDataVersion, domain.German, d.productName, d.productVersion, ) syncMessage.TanRequest = d.hbciVersion.TanProcess4Request(segment.IdentificationID) syncMessage.Sync = d.hbciVersion.SynchronisationRequest(segment.SyncModeAquireClientID) @@ -258,7 +264,7 @@ func (d *dialog) anonymousInit() error { initMessage := message.NewDialogInitializationClientMessage(d.hbciVersion) initMessage.Identification = segment.NewIdentificationSegment(d.BankID, anonymousClientID, initialClientSystemID, false) initMessage.ProcessingPreparation = segment.NewProcessingPreparationSegmentV3( - d.BankParameterDataVersion(), d.UserParameterDataVersion(), d.Language, + d.BankParameterDataVersion(), d.UserParameterDataVersion(), d.Language, d.productName, d.productVersion, ) initMessage.BasicMessage = d.newBasicMessage(initMessage) initMessage.SetSegmentPositions() @@ -341,7 +347,7 @@ func (d *dialog) init() error { initMessage := message.NewDialogInitializationClientMessage(d.hbciVersion) initMessage.Identification = segment.NewIdentificationSegment(d.BankID, d.clientID, d.ClientSystemID, true) initMessage.ProcessingPreparation = segment.NewProcessingPreparationSegmentV3( - d.BankParameterDataVersion(), d.UserParameterDataVersion(), d.Language, + d.BankParameterDataVersion(), d.UserParameterDataVersion(), d.Language, d.productName, d.productVersion, ) initMessage.TanRequest = d.hbciVersion.TanProcess4Request(segment.IdentificationID) initMessage.BasicMessage = d.newBasicMessage(initMessage) diff --git a/dialog/pin_tan_dialog.go b/dialog/pin_tan_dialog.go index aa4cc18..6bb3025 100644 --- a/dialog/pin_tan_dialog.go +++ b/dialog/pin_tan_dialog.go @@ -14,11 +14,13 @@ import ( // Config contains the configuration of a PinTanDialog type Config struct { - BankID domain.BankID - HBCIURL string - UserID string - HBCIVersion segment.HBCIVersion - Transport transport.Transport + BankID domain.BankID + HBCIURL string + UserID string + HBCIVersion segment.HBCIVersion + ProductName string + ProductVersion string + Transport transport.Transport } // NewPinTanDialog creates a new dialog to use for pin/tan transport @@ -33,6 +35,8 @@ func NewPinTanDialog(config Config) *PinTanDialog { config.HBCIURL, config.UserID, config.HBCIVersion, + config.ProductName, + config.ProductVersion, signatureProvider, cryptoProvider, ), diff --git a/dialog/rdh_dialog.go b/dialog/rdh_dialog.go index 1a0ac51..291d176 100644 --- a/dialog/rdh_dialog.go +++ b/dialog/rdh_dialog.go @@ -7,7 +7,7 @@ import ( ) // NewRDHDialog creates a dialog to use with cardreader flow -func NewRDHDialog(bankID domain.BankID, hbciURL string, clientID string, hbciVersion segment.HBCIVersion) Dialog { +func NewRDHDialog(bankID domain.BankID, hbciURL string, clientID string, hbciVersion segment.HBCIVersion, productName string, productVersion string) Dialog { key, err := domain.GenerateSigningKey() if err != nil { panic(err) @@ -15,7 +15,7 @@ func NewRDHDialog(bankID domain.BankID, hbciURL string, clientID string, hbciVer signingKey := domain.NewRSAKey(key, domain.NewInitialKeyName(bankID.CountryCode, bankID.ID, clientID, "S")) provider := message.NewRDHSignatureProvider(signingKey, 12345) d := &rdhDialog{ - dialog: newDialog(bankID, hbciURL, clientID, hbciVersion, provider, nil), + dialog: newDialog(bankID, hbciURL, clientID, hbciVersion, productName, productVersion, provider, nil), } return d } diff --git a/segment/dialog.go b/segment/dialog.go index 155d18c..9f7fef1 100644 --- a/segment/dialog.go +++ b/segment/dialog.go @@ -6,8 +6,8 @@ import ( "github.com/mitch000001/go-hbci/element" ) -const productName = "5A624F86A785F4024DD914404" -const productVersion = hbci.Version +const defaultProductName = "5A624F86A785F4024DD914404" +const defaultProductVersion = hbci.Version func NewDialogEndSegment(dialogId string) *DialogEndSegment { d := &DialogEndSegment{ @@ -35,7 +35,13 @@ func (d *DialogEndSegment) elements() []element.DataElement { const ProcessingPreparationID = "HKVVB" -func NewProcessingPreparationSegmentV2(bdpVersion int, udpVersion int, language domain.Language) *ProcessingPreparationSegmentV2 { +func NewProcessingPreparationSegmentV2(bdpVersion int, udpVersion int, language domain.Language, productName string, productVersion string) *ProcessingPreparationSegmentV2 { + if productName == "" { + productName = defaultProductName + } + if productVersion == "" { + productVersion = defaultProductVersion + } p := &ProcessingPreparationSegmentV2{ BPDVersion: element.NewNumber(bdpVersion, 3), UPDVersion: element.NewNumber(udpVersion, 3), @@ -47,7 +53,13 @@ func NewProcessingPreparationSegmentV2(bdpVersion int, udpVersion int, language return p } -func NewProcessingPreparationSegmentV3(bdpVersion int, udpVersion int, language domain.Language) *ProcessingPreparationSegmentV3 { +func NewProcessingPreparationSegmentV3(bdpVersion int, udpVersion int, language domain.Language, productName string, productVersion string) *ProcessingPreparationSegmentV3 { + if productName == "" { + productName = defaultProductName + } + if productVersion == "" { + productVersion = defaultProductVersion + } p := &ProcessingPreparationSegmentV3{ BPDVersion: element.NewNumber(bdpVersion, 3), UPDVersion: element.NewNumber(udpVersion, 3),