From: Henryk Plötz Date: Sun, 26 Aug 2018 12:19:39 +0000 (+0200) Subject: Make it possible to open an anonymous dialogue (user_id=CUSTOMER_ID_ANONYMOUS, pin... X-Git-Tag: v2.0.0~1^2~78 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=06a3f1cd56d70c2511114a5231bfff1fa68f394f;p=thirdparty%2Fpython-fints.git Make it possible to open an anonymous dialogue (user_id=CUSTOMER_ID_ANONYMOUS, pin=None) --- diff --git a/fints/client.py b/fints/client.py index ebc7780..f84d187 100644 --- a/fints/client.py +++ b/fints/client.py @@ -13,7 +13,7 @@ from .dialog import FinTSDialog, FinTSDialogOLD from .formals import ( KTI1, Account3, BankIdentifier, SynchronisationMode, TwoStepParametersCommon, - TANMediaType2, TANMediaClass4, + TANMediaType2, TANMediaClass4, CUSTOMER_ID_ANONYMOUS, ) from .message import FinTSInstituteMessage, FinTSMessageOLD from .models import ( @@ -24,7 +24,7 @@ from .security import ( PinTanDummyEncryptionMechanism, PinTanOneStepAuthenticationMechanism, PinTanTwoStepAuthenticationMechanism, ) -from .segments import HIBPA3, HIRMG2, HIRMS2, HIUPA4, HIPINS1 +from .segments import HIBPA3, HIRMG2, HIRMS2, HIUPA4, HIPINS1, HKKOM4 from .segments.accounts import HISPA1, HKSPA, HKSPA1 from .segments.auth import HKTAB, HKTAN, HKTAB4, HKTAB5, HKTAN3, HKTAN5 from .segments.depot import HKWPD5, HKWPD6 @@ -369,6 +369,21 @@ class FinTS3Client: logger.debug('No HIWPD response segment found - maybe account has no holdings?') return [] + def get_communication_endpoints(self): + with self._get_dialog() as dialog: + hkkom = self._find_highest_supported_command(HKKOM4) + #hkkom = HKKOM4 + + responses = self._fetch_with_touchdowns( + dialog, + lambda touchdown: hkkom( + touchdown_point=touchdown, + ), + 'HIKOM' + ) + + return responses + def start_simple_sepa_transfer(self, account: SEPAAccount, iban: str, bic: str, recipient_name: str, amount: Decimal, account_name: str, reason: str, endtoend_id='NOTPROVIDED'): @@ -618,7 +633,7 @@ IMPLEMENTED_HKTAN_VERSIONS = { class FinTS3PinTanClient(FinTS3Client): def __init__(self, bank_identifier, user_id, pin, server, customer_id=None, *args, **kwargs): - self.pin = Password(pin) + self.pin = Password(pin) if pin is not None else pin self._pending_tan = None self.connection = FinTSHTTPSConnection(server) self.allowed_security_functions = [] @@ -627,25 +642,28 @@ class FinTS3PinTanClient(FinTS3Client): super().__init__(bank_identifier=bank_identifier, user_id=user_id, customer_id=customer_id, *args, **kwargs) def _new_dialog(self, lazy_init=False): - if not self.selected_security_function or self.selected_security_function == '999': + if self.pin is None: + enc = None + auth = [] + elif not self.selected_security_function or self.selected_security_function == '999': enc = PinTanDummyEncryptionMechanism(1) - auth = PinTanOneStepAuthenticationMechanism(self.pin) + auth = [PinTanOneStepAuthenticationMechanism(self.pin)] else: enc = PinTanDummyEncryptionMechanism(2) - auth = PinTanTwoStepAuthenticationMechanism( + auth = [PinTanTwoStepAuthenticationMechanism( self, self.selected_security_function, self.pin, - ) + )] return FinTSDialog(self, lazy_init=lazy_init, enc_mechanism=enc, - auth_mechanisms=[auth], + auth_mechanisms=auth, ) def _ensure_system_id(self): - if self.system_id != SYSTEM_ID_UNASSIGNED: + if self.system_id != SYSTEM_ID_UNASSIGNED or self.user_id == CUSTOMER_ID_ANONYMOUS: return with self._get_dialog(lazy_init=True) as dialog: diff --git a/fints/dialog.py b/fints/dialog.py index 0f1edb7..500841c 100644 --- a/fints/dialog.py +++ b/fints/dialog.py @@ -3,7 +3,7 @@ import pickle import io from .formals import ( - BankIdentifier, Language2, SynchronisationMode, SystemIDStatus, + BankIdentifier, Language2, SynchronisationMode, SystemIDStatus, CUSTOMER_ID_ANONYMOUS, ) from .message import ( FinTSCustomerMessage, FinTSMessage, FinTSMessageOLD, MessageDirection, @@ -59,7 +59,7 @@ class FinTSDialog: self.client.bank_identifier, self.client.customer_id, self.client.system_id, - SystemIDStatus.ID_NECESSARY + SystemIDStatus.ID_NECESSARY if self.client.customer_id != CUSTOMER_ID_ANONYMOUS else SystemIDStatus.ID_UNNECESSARY ), HKVVB3( self.client.bpd_version, @@ -110,14 +110,14 @@ class FinTSDialog: self.finish_message(message) assert message.segments[0].message_number == self.next_message_number[message.DIRECTION] - self.messages[message.segments[0].message_number] = message + self.messages[message.DIRECTION][message.segments[0].message_number] = message self.next_message_number[message.DIRECTION] += 1 response = self.client.connection.send(message) ##assert response.segments[0].message_number == self.next_message_number[response.DIRECTION] # FIXME Better handling of HKEND in exception case - self.messages[response.segments[0].message_number] = message + self.messages[response.DIRECTION][response.segments[0].message_number] = response self.next_message_number[response.DIRECTION] += 1 if self.enc_mechanism: diff --git a/fints/formals.py b/fints/formals.py index fdd8e52..b3791fd 100644 --- a/fints/formals.py +++ b/fints/formals.py @@ -4,6 +4,7 @@ from fints.types import * # The order is important! from fints.fields import * from fints.utils import RepresentableEnum, ShortReprMixin +CUSTOMER_ID_ANONYMOUS = '9999999999' class DataElementGroup(Container): pass @@ -254,7 +255,7 @@ class TwoStepParameters5(TwoStepParametersCommon): max_length_input = DataElementField(type='num', max_length=2, _d="Maximale Länge des Eingabewertes im Zwei-Schritt-Verfahren") allowed_format = CodeField(enum=AllowedFormat, length=1, _d="Erlaubtes Format im Zwei-Schritt-Verfahren") text_return_value = DataElementField(type='an', max_length=30, _d="Text zur Belegung des Rückgabewertes im Zwei-Schritt-Verfahren") - max_length_return_value = DataElementField(type='num', max_length=3, _d="Maximale Länge des Rückgabewertes im Zwei-Schritt-Verfahren") + max_length_return_value = DataElementField(type='num', max_length=4, _d="Maximale Länge des Rückgabewertes im Zwei-Schritt-Verfahren") number_of_supported_lists = DataElementField(type='num', length=1, _d="Anzahl unterstützter aktiver TAN-Listen") multiple_tans_allowed = DataElementField(type='jn', _d="Mehrfach-TAN erlaubt") tan_time_dialog_association = CodeField(enum=TANTimeDialogAssociation, length=1, _d="TAN Zeit- und Dialogbezug") @@ -275,7 +276,7 @@ class TwoStepParameters6(TwoStepParametersCommon): max_length_input = DataElementField(type='num', max_length=2, _d="Maximale Länge des Eingabewertes im Zwei-Schritt-Verfahren") allowed_format = CodeField(enum=AllowedFormat, length=1, _d="Erlaubtes Format im Zwei-Schritt-Verfahren") text_return_value = DataElementField(type='an', max_length=30, _d="Text zur Belegung des Rückgabewertes im Zwei-Schritt-Verfahren") - max_length_return_value = DataElementField(type='num', max_length=3, _d="Maximale Länge des Rückgabewertes im Zwei-Schritt-Verfahren") + max_length_return_value = DataElementField(type='num', max_length=4, _d="Maximale Länge des Rückgabewertes im Zwei-Schritt-Verfahren") multiple_tans_allowed = DataElementField(type='jn', _d="Mehrfach-TAN erlaubt") tan_time_dialog_association = CodeField(enum=TANTimeDialogAssociation, length=1, _d="TAN Zeit- und Dialogbezug") cancel_allowed = DataElementField(type='jn', _d="Auftragsstorno erlaubt") @@ -688,3 +689,18 @@ class BatchTransferParameter1(DataElementGroup): max_transfer_count = DataElementField(type='num', max_length=7, _d="Maximale Anzahl CreditTransferTransactionInformation") sum_amount_required = DataElementField(type='jn', _d="Summenfeld benötigt") single_booking_allowed = DataElementField(type='jn', _d="Einzelbuchung erlaubt") + +class ServiceType2(RepresentableEnum): + T_ONLINE = 1 #: T-Online + TCP_IP = 2 #: TCP/IP (Protokollstack SLIP/PPP) + HTTPS = 3 #: https + +class CommunicationParameter2(DataElementGroup): + """Kommunikationsparameter, version 2 + + Source: FinTS Financial Transaction Services, Schnittstellenspezifikation, Formals""" + service_type = IntCodeField(enum=ServiceType2, max_length=2, _d="Kommunikationsdienst") + address = DataElementField(type='an', max_length=512, _d="Kommunikationsadresse") + address_adjunct = DataElementField(type='an', max_length=512, required=False, _d="Kommunikationsadresszusatz") + filter_function = DataElementField(type='an', length=3, required=False, _d="Filterfunktion") + filter_function_version = DataElementField(type='num', max_length=3, required=False, _d="Version der Filterfunktion") diff --git a/fints/segments/__init__.py b/fints/segments/__init__.py index 3fb0cd9..e7f101c 100644 --- a/fints/segments/__init__.py +++ b/fints/segments/__init__.py @@ -11,7 +11,7 @@ from fints.formals import ( SecurityClass, SecurityDateTime, SecurityIdentificationDetails, SecurityProfile, SecurityRole, SegmentHeader, SegmentSequenceField, SignatureAlgorithm, SupportedHBCIVersions2, SupportedLanguages2, UPDUsage, - UserDefinedSignature, + UserDefinedSignature, Language2, CommunicationParameter2, ) from fints.utils import SubclassesMixin, classproperty @@ -160,6 +160,23 @@ class HIBPA3(FinTS3Segment): min_timeout = DataElementField(type='num', max_length=4, required=False, _d="Minimaler Timeout-Wert") max_timeout = DataElementField(type='num', max_length=4, required=False, _d="Maximaler Timeout-Wert") +class HKKOM4(FinTS3Segment): + """Kommunikationszugang anfordern, version 4 + + Source: FinTS Financial Transaction Services, Schnittstellenspezifikation, Formals""" + start_bank_identifier = DataElementGroupField(type=BankIdentifier, required=False, _d="Von Kreditinstitutskennung") + end_bank_identifier = DataElementGroupField(type=BankIdentifier, required=False, _d="Bis Kreditinstitutskennung") + max_number_responses = DataElementField(type='num', max_length=4, required=False, _d="Maximale Anzahl Einträge") + touchdown_point = DataElementField(type='an', max_length=35, required=False, _d="Aufsetzpunkt") + +class HIKOM4(FinTS3Segment): + """Kommunikationszugang rückmelden, version 4 + + Source: FinTS Financial Transaction Services, Schnittstellenspezifikation, Formals""" + bank_identifier = DataElementGroupField(type=BankIdentifier, _d="Kreditinstitutskennung") + default_language = CodeField(enum=Language2, max_length=3, _d="Standardsprache") + communication_parameters = DataElementGroupField(type=CommunicationParameter2, min_count=1, max_count=9, _d="Kommunikationsparameter") + from . import ( accounts, auth, debit, depot, dialog, message, saldo, statement, transfer, ) diff --git a/fints/utils.py b/fints/utils.py index 00dd504..3f045f8 100644 --- a/fints/utils.py +++ b/fints/utils.py @@ -284,7 +284,7 @@ class Password(str): cls.protected = False def __str__(self): - return '***' if self.protected else self.value + return '***' if self.protected else str(self.value) def __repr__(self): return self.__str__().__repr__()