Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions fints/client.py
Original file line number Diff line number Diff line change
Expand Up @@ -1305,6 +1305,9 @@ def fetch_tan_mechanisms(self):
else:
self.set_tan_mechanism('999')
self._ensure_system_id()
# Bootstrap phase (anonymous dialog with sf=999) is complete.
# Reset so that errors in subsequent authenticated dialogs are properly raised.
self._bootstrap_mode = False
Comment on lines +1308 to +1310

@mt-software-de mt-software-de Oct 18, 2026 •

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks for this, the bootstrap part solves a problem we ran into as well. It doesn't cover clients restored with from_data, which usually don't call fetch_tan_mechanisms() again and so stay in bootstrap mode, swallowing a 9075. I opened #228, which ends the bootstrap mode in __enter__ instead and covers both cases.

For what it's worth, we can also confirm the security profile change with Consorsbank: PIN:1 in HNSHK is rejected with 9010 Ungültiger Signaturaufbau, PIN:2 works.

if self.get_current_tan_mechanism():
# We already got a reply through _ensure_system_id
return self.get_current_tan_mechanism()
Expand Down
4 changes: 3 additions & 1 deletion fints/security.py
Original file line number Diff line number Diff line change
Expand Up @@ -99,13 +99,14 @@ def __init__(self, pin):
self.pin = pin
self.pending_signature = None
self.security_function = None
self.security_method_version = 1

def sign_prepare(self, message: FinTSMessage):
_now = datetime.datetime.now()
rand = random.SystemRandom()

self.pending_signature = HNSHK4(
security_profile=SecurityProfile(SecurityMethod.PIN, 1),
security_profile=SecurityProfile(SecurityMethod.PIN, self.security_method_version),
security_function=self.security_function,
security_reference=rand.randint(1000000, 9999999),
security_application_area=SecurityApplicationArea.SHM,
Expand Down Expand Up @@ -178,6 +179,7 @@ def __init__(self, client, security_function, *args, **kwargs):
super().__init__(*args, **kwargs)
self.client = client
self.security_function = security_function
self.security_method_version = 2

def _get_tan(self):
retval = self.client._pending_tan
Expand Down