]> git.ipfire.org Git - thirdparty/python-fints.git/commitdiff
Make it possible to open an anonymous dialogue (user_id=CUSTOMER_ID_ANONYMOUS, pin...
authorHenryk Plötz <henryk@ploetzli.ch>
Sun, 26 Aug 2018 12:19:39 +0000 (14:19 +0200)
committerRaphael Michel <mail@raphaelmichel.de>
Mon, 3 Dec 2018 18:34:29 +0000 (19:34 +0100)
fints/client.py
fints/dialog.py
fints/formals.py
fints/segments/__init__.py
fints/utils.py

index ebc7780eb40c8696bb6253ac1fb6cb07d5464bc1..f84d187cc53e5b86a15502a68085a8652226a91d 100644 (file)
@@ -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:
index 0f1edb70fe2ecdf4608ac45f17823738b8601977..500841c72ffa556bc03a0c98e1f57a053ab5756d 100644 (file)
@@ -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:
index fdd8e527b53b2bb7d0fa4f88de1099cc219258aa..b3791fde3d497b0f7f6ff796401592967726bc46 100644 (file)
@@ -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")
index 3fb0cd9d2884201b795ce78d41c9446955928e06..e7f101c971d37ed5902f9cedc54cac9780200db8 100644 (file)
@@ -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,
 )
index 00dd504fc902985b394470f878ea3098f0142816..3f045f858d72ee0604de8ecc46b244aa5ada5666 100644 (file)
@@ -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__()