diff --git a/fints/client.py b/fints/client.py index 213972a..1e37369 100644 --- a/fints/client.py +++ b/fints/client.py @@ -1273,6 +1273,21 @@ def __init__(self, bank_identifier, user_id, pin, server, customer_id=None, tan_ self._bootstrap_mode = True super().__init__(bank_identifier=bank_identifier, user_id=user_id, customer_id=customer_id, *args, **kwargs) + def process_response_message(self, dialog, message: FinTSInstituteMessage, internal_send=True): + previous_sca_required_response = getattr(self, "_processing_sca_required_response", False) + self._processing_sca_required_response = self._message_has_sca_required_response(message) + try: + return super().process_response_message(dialog, message, internal_send=internal_send) + finally: + self._processing_sca_required_response = previous_sca_required_response + + def _message_has_sca_required_response(self, message): + for seg in list(message.find_segments(HIRMG2)) + list(message.find_segments(HIRMS2)): + for response in seg.responses: + if response.code == '9075': + return True + return False + def _new_dialog(self, lazy_init=False): if self.pin is None: enc = None @@ -1601,7 +1616,16 @@ def _process_response(self, dialog, segment, response): raise FinTSClientError("Error during dialog initialization, could not fetch BPD. Please check that you " "passed the correct bank identifier to the HBCI URL of the correct bank.") - if ((not dialog.open and response.code.startswith('9')) and not self._bootstrap_mode) or response.code in ('9340', '9910', '9930', '9931', '9942'): + sca_required_in_message = getattr(self, "_processing_sca_required_response", False) + if ( + ( + not dialog.open + and response.code.startswith('9') + and not self._bootstrap_mode + and not sca_required_in_message + ) + or response.code in ('9340', '9910', '9930', '9931', '9942') + ): # Assume all 9xxx errors in a not-yet-open dialog refer to the PIN or authentication # During a dialog also listen for the following codes which may explicitly indicate an # incorrect pin: 9340, 9910, 9930, 9931, 9942 diff --git a/tests/test_client.py b/tests/test_client.py index f602e4f..514913d 100644 --- a/tests/test_client.py +++ b/tests/test_client.py @@ -1,5 +1,6 @@ from fints.client import FinTS3PinTanClient, TransactionResponse, NeedTANResponse, ResponseStatus, NeedRetryResponse -from fints.exceptions import FinTSClientPINError, FinTSClientTemporaryAuthError +from fints.exceptions import FinTSClientPINError, FinTSClientTemporaryAuthError, FinTSSCARequiredError +from fints.parser import FinTS3Parser from decimal import Decimal import pytest @@ -73,6 +74,27 @@ def test_pin_locked(fints_server): str(client.pin) +def test_sca_required_takes_precedence_over_unopened_dialog_error(fints_server): + client = FinTS3PinTanClient( + '12345678', + 'test1', + '1234', + fints_server, + product_id="TEST-123", product_version="1.2.3", + ) + client._bootstrap_mode = False + dialog = type("Dialog", (), {"open": False})() + message = FinTS3Parser().parse_message( + b"HIRMG:3:2+9050::Nachricht enthaelt Fehler.'" + b"HIRMS:4:2:3+9075::Starke Kundenauthentifizierung notwendig.'" + ) + + with pytest.raises(FinTSSCARequiredError): + client.process_response_message(dialog, message) + + assert not client.pin.blocked + + def test_resume(fints_client, fints_server): with fints_client: system_id = fints_client.system_id