Skip to content

Commit c272ae1

Browse files
rhnmorremeyer
andauthored
Add Comdirect (#194)
* add util function to decode photoTAN images * Add comdirect to tested banks --------- Co-authored-by: Morre <[email protected]>
1 parent 4f4f278 commit c272ae1

File tree

4 files changed

+74
-1
lines changed

4 files changed

+74
-1
lines changed

docs/tans.rst

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -91,6 +91,21 @@ a file:
9191
writer.write(result.challenge_matrix[1])
9292
writer.close()
9393
94+
Some banks, like Comdirect, may provide the challenge within the ``challenge_hhduc`` attribute. We provide a helper function to decode the challenge. Pass the ``challenge_hhduc`` value to this method:
95+
96+
.. autofunction:: fints.hhd.utils.decode_phototan_image
97+
98+
This returns a dictionary with a ``mime_type`` and an ``image`` field. The ``image`` field contains the binary data
99+
of the image itself and can e.g. be written to a file
100+
101+
.. code-block:: python
102+
from fints.utils import decode_phototan_image
103+
104+
data = decode_phototan_image(challenge_hhduc)
105+
writer = open("tan.png", "wb")
106+
writer.write(data["image"])
107+
writer.close()
108+
94109
Sending the TAN
95110
---------------
96111

docs/tested.rst

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@ Bank Transactions Holdings Transfer Debits
1010
Postbank Yes
1111
BBBank eG Yes Yes
1212
Sparkasse Heidelberg Yes
13-
comdirect Yes
13+
comdirect Yes Yes
1414
======================================== ============ ======== ======== ======
1515

1616
Tested security functions

fints/utils.py

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -351,3 +351,34 @@ def changed(reduced=False):
351351
except ImportError:
352352
def doc_enum(an_enum: EnumType) -> EnumType:
353353
return an_enum
354+
355+
356+
def decode_phototan_image(data):
357+
"""
358+
This decodes photoTAN data sent as challenge_hhduc into its mime type and the actual image data.
359+
360+
:returns: a dictionary with two values, 'mime_type' and 'image'
361+
:rtype: dict
362+
363+
The markup of the data is taken from https://github.com/hbci4j/hbci4java/blob/c8eabe6809e8d0271f944ea28a59ed6b736af56e/src/main/java/org/kapott/hbci/manager/MatrixCode.java#L61-L97
364+
The encoding is taken from https://github.com/hbci4j/hbci4java/blob/c8eabe6809e8d0271f944ea28a59ed6b736af56e/src/main/java/org/kapott/hbci/comm/Comm.java#L46
365+
"""
366+
# Mime type length is the first two bytes of data
367+
mime_type_length = int.from_bytes(data[:2], byteorder='big')
368+
369+
# The mime type follows from byte three to (mime_type_length - 1)
370+
mime_type = data[2:2 + mime_type_length].decode("iso-8859-1")
371+
372+
# The image length is coded in the next two bytes
373+
image_length_start = 2 + mime_type_length
374+
image_length = int.from_bytes(data[image_length_start:2 + image_length_start], byteorder='big')
375+
376+
# The actual image data is everything that follows.
377+
# To be compatible with possible future extensions, we still slice the data
378+
image = data[2 + image_length_start: 2 + image_length_start + image_length]
379+
380+
return {
381+
"mime_type": mime_type,
382+
"image": image
383+
}
384+

tests/test_utils.py

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
import pytest
2+
from fints.utils import decode_phototan_image
3+
4+
5+
# HITAN3:
6+
# 'challenge' contains a HHD 1.3 code embedded in the normal text payload
7+
# field.
8+
# Example: 'CHLGUC 00312908881344731012345678900515,00CHLGTEXT0292Sie haben eine ...'
9+
# The code in NeedTANResponse._parse_tan_challenge extracts
10+
# '2908881344731012345678900515,00'
11+
# from this, as a version 1.3 code. parse() should accept it
12+
# (start code: '88134473', IBAN: '1234567890', amount: '15,00')
13+
14+
# HITAN6:
15+
# 'challenge' contains 4 fields:
16+
# 2 bytes: mime type length
17+
# x bytes (see above): mime type
18+
# 2 bytes: data length
19+
# y bytes: image data
20+
21+
CHALLENGE = b'\x00\timage/png\x0e\x82\x89PNG\r\n\x1a\n\x00\x00\x00\rIHDR\x00\x00\x00\xc8\x00\x00\x00\xc8\x08\x06\x00\x00\x00\xadX\xae\x9e\x00\x00\x00\x06bKGD\x00\xff\x00\xff\x00\xff\xa0\xbd\xa7\x93\x00\x00\x02MIDATx\x9c\xed\xdd\xb1\r\xc40\x0c\x04A\xea\xe1\xfe[\xf6w\xb0\x89\x023\x98\xa9@ \xb0Pxgf\xdeY\xec}W?o\xce9_?!\xb9\xdf\x9d\xdf\xd7\x0f\x80\xcd\x04\x02A \x10\x04\x02A \x10\x04\x02A \x10\x04\x02A \x10\x04\x02A \x10\x04\x02A \x10\x04\x02A \x10\x04\x02A \x10\x04\x02A \x10\x04\x02A \x10\x04\x02A \x10\x04\x02A \x10\x04\x02A \x10\x04\x02A \x10\x04\x02A \x10\x04\x02A \x10\x04\x02A \x10\x04\x02A \x10\x04\x02A \x10\x1e;\xdaw\xdc\xef\xce\xf6\xfb\xf9A \x08\x04\x82@ \x08\x04\x82@ \x08\x04\x82@ \x08\x04\x82@ \x08\x04\x82@ \x08\x04\x82@ \x08\x04\x82@ \x08\x04\x82@ \x08\x04\x82@ \x08\x04\x82@ \x08\x04\x82@ \x08\x04\x82@ \x08\x04\x82@ \x08\x04\x82@ \x08\x04\x82@ \x08\x04\x82@ \x08\x04\x82@ \x08\x04\x82@ \x08\x04\x82@ \x9c\x99Y=T\xbd}G\xdb\x0e\xf9\x9d\xed\xf7\xf3\x83@\x10\x08\x04\x81@\x10\x08\x04\x81@\x10\x08\x04\x81@\x10\x08\x04\x81@\x10\x08\x04\x81@\x10\x08\x04\x81@\x10\x08\x04\x81@\x10\x08\x04\x81@\x10\x08\x04\x81@\x10\x08\x04\x81@\x10\x08\x04\x81@\x10\x08\x04\x81@\x10\x08\x04\x81@\x10\x08\x04\x81@\x10\x08\x04\x81@\x10\x08\x04\x81@\x10\x08\x04\x81@\x10\x08\x04\x81@\x10\x08\x04\x81@x\xech\xdfq\xbf;\xdb\xef\xe7\x07\x81 \x10\x08\x02\x81 \x10\x08\x02\x81 \x10\x08\x02\x81 \x10\x08\x02\x81 \x10\x08\x02\x81 \x10\x08\x02\x81 \x10\x08\x02\x81 \x10\x08\x02\x81 \x10\x08\x02\x81 \x10\x08\x02\x81 \x10\x08\x02\x81 \x10\x08\x02\x81 \x10\x08\x02\x81 \x10\x08\x02\x81 \x10\x08\x02\x81 \x10\x08\x02\x81 \x10\x08\x02\x81 \x10\x08\x02\x81 \x10\x08\x02\x81pff\xf5P\xf5\xf6\x1dm;\xe4w\xb6\xdf\xcf\x0f\x02A \x10\x04\x02A \x10\x04\x02A \x10\x04\x02A \x10\x04\x02A \x10\x04\x02A \x10\x04\x02A \x10\x04\x02A \x10\x04\x02A \x10\x04\x02A \x10\x04\x02A \x10\x04\x02A \x10\x04\x02A \x10\x04\x02A \x10\x04\x02A \x10\x04\x02A \x10\x04\x02A \x10\x04\x02A \x10\x04\x02A \x10\x04\x02\xe1\x0fp-(\x89A#\xd8\xc6\x00\x00\x00\x00IEND\xaeB`\x82'
22+
23+
def test_decode_phototan_image():
24+
data = decode_phototan_image(CHALLENGE)
25+
26+
assert data["mime_type"] == "image/png"
27+
assert data["image"] == b'\x89PNG\r\n\x1a\n\x00\x00\x00\rIHDR\x00\x00\x00\xc8\x00\x00\x00\xc8\x08\x06\x00\x00\x00\xadX\xae\x9e\x00\x00\x00\x06bKGD\x00\xff\x00\xff\x00\xff\xa0\xbd\xa7\x93\x00\x00\x02MIDATx\x9c\xed\xdd\xb1\r\xc40\x0c\x04A\xea\xe1\xfe[\xf6w\xb0\x89\x023\x98\xa9@ \xb0Pxgf\xdeY\xec}W?o\xce9_?!\xb9\xdf\x9d\xdf\xd7\x0f\x80\xcd\x04\x02A \x10\x04\x02A \x10\x04\x02A \x10\x04\x02A \x10\x04\x02A \x10\x04\x02A \x10\x04\x02A \x10\x04\x02A \x10\x04\x02A \x10\x04\x02A \x10\x04\x02A \x10\x04\x02A \x10\x04\x02A \x10\x04\x02A \x10\x04\x02A \x10\x04\x02A \x10\x04\x02A \x10\x04\x02A \x10\x04\x02A \x10\x1e;\xdaw\xdc\xef\xce\xf6\xfb\xf9A \x08\x04\x82@ \x08\x04\x82@ \x08\x04\x82@ \x08\x04\x82@ \x08\x04\x82@ \x08\x04\x82@ \x08\x04\x82@ \x08\x04\x82@ \x08\x04\x82@ \x08\x04\x82@ \x08\x04\x82@ \x08\x04\x82@ \x08\x04\x82@ \x08\x04\x82@ \x08\x04\x82@ \x08\x04\x82@ \x08\x04\x82@ \x08\x04\x82@ \x08\x04\x82@ \x9c\x99Y=T\xbd}G\xdb\x0e\xf9\x9d\xed\xf7\xf3\x83@\x10\x08\x04\x81@\x10\x08\x04\x81@\x10\x08\x04\x81@\x10\x08\x04\x81@\x10\x08\x04\x81@\x10\x08\x04\x81@\x10\x08\x04\x81@\x10\x08\x04\x81@\x10\x08\x04\x81@\x10\x08\x04\x81@\x10\x08\x04\x81@\x10\x08\x04\x81@\x10\x08\x04\x81@\x10\x08\x04\x81@\x10\x08\x04\x81@\x10\x08\x04\x81@\x10\x08\x04\x81@\x10\x08\x04\x81@\x10\x08\x04\x81@x\xech\xdfq\xbf;\xdb\xef\xe7\x07\x81 \x10\x08\x02\x81 \x10\x08\x02\x81 \x10\x08\x02\x81 \x10\x08\x02\x81 \x10\x08\x02\x81 \x10\x08\x02\x81 \x10\x08\x02\x81 \x10\x08\x02\x81 \x10\x08\x02\x81 \x10\x08\x02\x81 \x10\x08\x02\x81 \x10\x08\x02\x81 \x10\x08\x02\x81 \x10\x08\x02\x81 \x10\x08\x02\x81 \x10\x08\x02\x81 \x10\x08\x02\x81 \x10\x08\x02\x81 \x10\x08\x02\x81pff\xf5P\xf5\xf6\x1dm;\xe4w\xb6\xdf\xcf\x0f\x02A \x10\x04\x02A \x10\x04\x02A \x10\x04\x02A \x10\x04\x02A \x10\x04\x02A \x10\x04\x02A \x10\x04\x02A \x10\x04\x02A \x10\x04\x02A \x10\x04\x02A \x10\x04\x02A \x10\x04\x02A \x10\x04\x02A \x10\x04\x02A \x10\x04\x02A \x10\x04\x02A \x10\x04\x02A \x10\x04\x02A \x10\x04\x02\xe1\x0fp-(\x89A#\xd8\xc6\x00\x00\x00\x00IEND\xaeB`\x82'

0 commit comments

Comments
 (0)