From: Raphael Michel Date: Wed, 25 Jul 2018 14:26:24 +0000 (+0200) Subject: Parse TAN challenge X-Git-Tag: v1.0.0~10 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=f4b52fcb792128def43b392da5755cc8d5c18715;p=thirdparty%2Fpython-fints.git Parse TAN challenge --- diff --git a/fints/client.py b/fints/client.py index 569d0dc..c00a8bb 100644 --- a/fints/client.py +++ b/fints/client.py @@ -10,7 +10,7 @@ from .connection import FinTSHTTPSConnection from .dialog import FinTSDialog from .message import FinTSMessage from .message import FinTSResponse -from .models import SEPAAccount, TANMethod +from .models import SEPAAccount, TANMethod, TANChallenge6, TANChallenge5, TANChallenge3, TANChallenge4 from .segments.accounts import HKSPA from .segments.auth import HKTAN, HKTAB from .segments.depot import HKWPD @@ -268,9 +268,9 @@ class FinTS3Client: return 'Ok' - def start_simple_sepa_transfer(self, account: SEPAAccount, tan_method, iban: str, bic: str, recipient_name: str, - amount: Decimal, account_name: str, reason: str, endtoend_id='NOTPROVIDED', - tan_description=''): + def start_simple_sepa_transfer(self, account: SEPAAccount, tan_method: TANMethod, iban: str, bic: str, + recipient_name: str, amount: Decimal, account_name: str, reason: str, + endtoend_id='NOTPROVIDED', tan_description=''): config = { "name": account_name, "IBAN": account.iban, @@ -290,33 +290,48 @@ class FinTS3Client: } sepa.add_payment(payment) xml = sepa.export().decode() - self.start_sepa_transfer(account, xml, tan_method, tan_description) + return self.start_sepa_transfer(account, xml, tan_method, tan_description) + + def _get_start_sepa_transfer_message(self, dialog, account: SEPAAccount, pain_message: str, tan_description): + segHKCCS = HKCCS(3, account, pain_message) + segHKTAN = HKTAN(4, 4, '', tan_description) + return self._new_message(dialog, [ + segHKCCS, + segHKTAN + ]) def start_sepa_transfer(self, account: SEPAAccount, pain_message: str, tan_method, tan_description=''): dialog = self._new_dialog() dialog.sync() - - dialog.tan_mechs = [tan_method.security_feature] + dialog.tan_mechs = [tan_method] dialog.init() - def _get_msg(): - segHKCCS = HKCCS(3, account, pain_message) - segHKTAN = HKTAN(4, 4, '', tan_description) - return self._new_message(dialog, [ - segHKCCS, - segHKTAN - ]) - with self.pin.protect(): - logger.debug('Sending HKCCS: {}'.format(_get_msg())) + logger.debug('Sending HKCCS: {}'.format(self._get_start_sepa_transfer_message( + dialog, account, pain_message, tan_description + ))) - resp = dialog.send(_get_msg()) + resp = dialog.send(self._get_start_sepa_transfer_message(dialog, account, pain_message, tan_description)) logger.debug('Got HKCCS response: {}'.format(resp)) - response = {} - response['response'] = resp - response['dialog'] = dialog - return response + seg = resp._find_segment('HITAN') + s = split_for_data_groups(seg) + spl = split_for_data_elements(s[0]) + if spl[2] == '3': + model = TANChallenge3 + elif spl[2] == '4': + model = TANChallenge4 + elif spl[2] == '5': + model = TANChallenge5 + elif spl[2] == '6': + model = TANChallenge6 + else: + raise NotImplementedError( + "HITAN segment version {} is currently not implemented".format( + spl[2] + ) + ) + return model(dialog, *s[1:1 + len(model.args)]) def get_tan_methods(self): dialog = self._new_dialog() diff --git a/fints/dialog.py b/fints/dialog.py index 7f1f05d..dc3c395 100644 --- a/fints/dialog.py +++ b/fints/dialog.py @@ -62,6 +62,7 @@ class FinTSDialog: self.bankname = resp.get_bank_name() self.hksalversion = resp.get_hksal_max_version() self.hkkazversion = resp.get_hkkaz_max_version() + self.hktanversion = resp._get_segment_max_version('HKTAN') self.tan_mechs = resp.get_supported_tan_mechanisms() logger.debug('Bank name: {}'.format(self.bankname)) @@ -69,6 +70,7 @@ class FinTSDialog: logger.debug('Dialog ID: {}'.format(self.dialogid)) logger.debug('HKKAZ max version: {}'.format(self.hkkazversion)) logger.debug('HKSAL max version: {}'.format(self.hksalversion)) + logger.debug('HKTAN max version: {}'.format(self.hktanversion)) logger.debug('TAN mechanisms: {}'.format(', '.join(str(t) for t in self.tan_mechs))) self.end() diff --git a/fints/message.py b/fints/message.py index 97af1b9..f75038a 100644 --- a/fints/message.py +++ b/fints/message.py @@ -66,7 +66,6 @@ class FinTSResponse: RE_UNWRAP = re.compile('HNVSD:\d+:\d+\+@\d+@(.+)\'\'') RE_SEGMENTS = re.compile("'(?=[A-Z]{4,}:\d|')") RE_SYSTEMID = re.compile("HISYN:\d+:\d+:\d+\+(.+)") - RE_TANMECH = re.compile('\d{3}') def __init__(self, data): self.response = self._unwrap(data) diff --git a/fints/models.py b/fints/models.py index 04071e0..4da5e5f 100644 --- a/fints/models.py +++ b/fints/models.py @@ -8,9 +8,7 @@ Holding = namedtuple('Holding', 'ISIN name market_value value_symbol valuation_date pieces total_value acquisitionprice') -class TANMethod: - args = ['security_feature'] - +class DataClass: def __init__(self, *args, **kwargs): for i, a in enumerate(args): setattr(self, self.args[i], a) @@ -21,12 +19,17 @@ class TANMethod: def __repr__(self): return '{}({})'.format( self.__class__.__name__, - ', '.join(['{}={}'.format(k, repr(getattr(self, k))) for k in self.args]) + ', '.join(['{}={}'.format(k, repr(getattr(self, k, None))) for k in self.args]) ) +class TANMethod(DataClass): + pass + + class TANMethod5(TANMethod): # Source: PIN/TAN docs – Verfahrensparameter Zwei-Schritt-Verfahren, Elementversion #5 + version = 5 args = ['security_feature', 'tan_process', 'tech_id', 'zka_id', 'zka_version', 'name', 'max_length_input', 'allowed_format', 'text_returnvalue', 'max_length_returnvalue', 'number_of_supported_lists', 'multiple_tans_allowed', 'tan_time_dialog_association', 'tan_list_number_required', 'cancel_allowed', @@ -36,9 +39,38 @@ class TANMethod5(TANMethod): class TANMethod6(TANMethod): # Source: PIN/TAN docs – Verfahrensparameter Zwei-Schritt-Verfahren, Elementversion #6 + version = 6 args = ['security_feature', 'tan_process', 'tech_id', 'zka_id', 'zka_version', 'name', 'max_length_input', 'allowed_format', 'text_returnvalue', 'max_length_returnvalue', 'multiple_tans_allowed', 'tan_time_dialog_association', 'cancel_allowed', 'sms_charge_account_required', 'principal_account_required', 'challenge_class_required', 'challenge_structured', 'initialization_mode', 'description_required', 'hhd_uc_required', 'supported_media_number'] + + +class TANChallenge(DataClass): + pass + + +class TANChallenge3(TANChallenge): + version = 3 + args = ['tan_process', 'request_hash', 'reference', 'challenge', 'challenge_datetime', + 'tan_list_number', 'ben', 'medium_description'] + + +class TANChallenge4(TANChallenge): + version = 4 + args = ['tan_process', 'request_hash', 'reference', 'challenge', 'challenge_hhd_uc', 'challenge_datetime', + 'tan_list_number', 'ben', 'medium_description'] + + +class TANChallenge5(TANChallenge): + version = 5 + args = ['tan_process', 'request_hash', 'reference', 'challenge', 'challenge_hhd_uc', 'challenge_datetime', + 'tan_list_number', 'ben', 'medium_description'] + + +class TANChallenge6(TANChallenge): + version = 6 + args = ['tan_process', 'request_hash', 'reference', 'challenge', 'challenge_hhd_uc', 'challenge_datetime', + 'medium_description'] \ No newline at end of file