Git Product home page Git Product logo

Comments (19)

guyyst avatar guyyst commented on June 20, 2024 1

Es spricht ja nichts dagegen ruhig beide Werte zu verwenden, falls irgendwann eine Bank doch unterschiedliche Wartzeiten erfordert. Hab die Änderungen hier in einer PR hochgeladen. Alles weitere lässt sich dann ja dort besprechen.

from hbci4java.

willuhn avatar willuhn commented on June 20, 2024

Die Prüfung, ob die Freigabe in der PushTAN App durchgeführt wurde, ist schlicht nicht implementiert, da das den Aufwand deutlich erhöht hätte. Du kannst mir hierzu gern einen PR senden, welcher diesen Fall mit berücksichtigt.

from hbci4java.

guyyst avatar guyyst commented on June 20, 2024

Danke für die schelle Antwort! Ich werde definitiv mal einen Blick in die Implementierung werfen.

Nach meiner naiven Vorstellung muss hierfür ja "nur" bei der 3956 Nachricht wiederholt der NEED_PT_DECOUPLED callback aufgerufen werden. Da fehlt mir aber vermutlich einfach das Verständnis in der Materie.

Hast du irgendwelche Tipps/Hinweise, weswegen das ganze eigentlich komplexer ist?

from hbci4java.

willuhn avatar willuhn commented on June 20, 2024

Du musst im Hintergrund einen zweiten Thread starten, den korrekt mit der aktuellen HBCI4Java-Session initialisieren und dann in zyklischen Abständen bei der Bank mit einem speziellen Dialog pollen, um den aktuellen Status abzufragen. Das gesamte Multi-Threading innerhalb einer HBCI-Session ist bisher gar nicht vorgesehen.

from hbci4java.

guyyst avatar guyyst commented on June 20, 2024

Ah, verstehe. Das ist in sofern interessant, als das ich für meinen use-case diese Library bereits in einem multithreading context verwende.

Ich starte den HBCI Dialog in einem neuen thread, welchen ich pausiere, wenn ein relevanter callback kommt. Dann kriegt der Nutzer im Frontend Bescheid, und mit der relevanten Antwort wird der thread, und damit auch der callback resumed.

Demnach war meine Vorstellung von der Decoupled Implementierung in HBCI4Java komplett ohne threads. Es würde einfach bei jedem callback Return nach NEED_PT_DECOUPLED der Status des Dialog's geprüft, und bei einer 3956 Antwort der selbe callback erneut aufgerufen. Ob das dann alle 5 Sekunden in einem neuen Thread, oder nur manuell nach Interaktion des user's passiert sollte dem Nutzer der Library überlassen sein.

Entspricht das einfach nicht deiner Vorstellung von dem Decoupled Feature, oder gibt es technische Gründe, weswegen eine solche Implementierung problematisch wäre?

from hbci4java.

willuhn avatar willuhn commented on June 20, 2024

Das weiss ich nicht. So genau habe ich das Thema nicht beleuchtet.

from hbci4java.

ahachmann avatar ahachmann commented on June 20, 2024

Hallo @guyyst
Ich sitze gerade selber an dem Thema und versuch die PushTan zu implementieren. Noch bin ich nicht an einem GV dran, sondern lediglich dabei ein Vertrauenswürdiges Gerät zu authorisieren. Dafür schaue ich grad in den HBCIUser rein, da die erste PushTan bereits beim fetchUPD auftritt.

Bist Du mit dem Thema weitergekommen? Ich frage mich derzeit generell zwei Dinge:

  1. Wie frage ich die Bank ab, ob die Pushnachricht bereits positiv in der App bestätigt wurde?
  2. Für GVs, wie würde ich eine solche Abfrage im Callback auslösen können?

Über einen Austausch würde ich mich sehr freuen.

Viele Grüße,
Alexander

from hbci4java.

guyyst avatar guyyst commented on June 20, 2024

Hallo @ahachmann, ich bin, wie in meinem oberen Kommentar als Idee erwähnt, einen "einfacheren" Weg gegangen, indem ich lediglich den selben Job, welcher aktuell ja bereits 1 mal nach einem NEED_PT_DECOUPLED callback ausgeführt wird, wiederhole, wenn die Response den code 3956 enthält.

Meine Lösung basiert also zu 100% darauf, dass Nutzer der Library bei jedem NEED_PT_DECOUPLED callback den thread für eine vernünftige Zeit pausieren, sonst pausiert die Library selbst, um Refresh-Spamming zu verhindern. Es wird keinerlei Multi-Threading in der library gemacht.

Mein erster Ansatz für diese Implementierung ist hier, mit dem relevanten Task-Redo code in GVTAN2Step.java. Der Redo-Teil ist eigentlich relativ kurz, das ganze drum-herum sind nur die checks der BPDs welche die Refresh-Parameter definieren.

Ich bin mir nicht sicher wie akzeptabel dieser Ansatz für die Library ist, oder ob eine komplexere Multi-Threading Lösung mit automatischem Background-Refreshing erforderlich ist. Für meine Zwecke ist die von mir implementiere Funktionalität genau richtig, da meine Programm sich bereits um das Multi-Threading kümmert.

@willuhn Vielleicht kannst du einen Blick drauf werfen und deine Meinung abgeben, bevor ich das ganze in einen Pull-Request Zustand bringe. Einige Fragen und Unsicherheiten habe ich eh noch bevor das ganze benutzbar wäre.

from hbci4java.

willuhn avatar willuhn commented on June 20, 2024

Danke für den Code-Vorschlag. Ich glaube, ich verstehe ihn aber noch nicht.

  • HBCI4Java müsste doch eigentlich zyklisch eine erneute dedizierte Nachricht mit dem HKTAN im Sinne von "Hat der User zwischenzeitlich bestätigt?" an die Bank senden. Das Senden dieser Nachricht ist in dem Code doch gar nicht enthalten. Wo passiert das denn?
  • Wenn die Bank im HITAN mit einem Code 3956 antwortet, um zu signalisieren, dass der User die Anfrage auf dem Smartphone noch nicht bestätigt hat, dann wird erneut ein Callback des Typs NEED_PT_DECOUPLED ausgelöst. Die Anwendung, welche HBCI4Java verwendet, kann dann aber nicht unterscheiden, ob es sich um eine erneute Rückfrage zu dem vorherigen Callback im Sinne von "Du hast im Smartphone immer noch nicht auf "OK" geklickt" handelt oder es die Anfrage für einen anderen Geschäftsvorfall ist. Die Anwendung sollte das unterscheiden können, um unterschiedliche Dialoge anzeigen zu können.
  • Dass das Warten per "Thread.sleep(sleepMs)" nur noch über die Rest-Zeit abzüglich Dauer des Callbacks passiert, finde ich eine gute Lösung. Auf die Weise hat die aufrufende Anwendung die Möglichkeit, dass Warten für den User zu visualisieren. Aus meiner Sicht wäre es hier sinnvoll, wenn die Anwendung die wartende Zeit mit übergeben bekommen würde. Dann wüsste sie, wie lange sie den User hinhalten muss, bevor der erneut auf "OK" klicken kann. Auch aufgrund des vorherigen Punkts wäre es vermutlich sinnvoll, einen zusätzlichen Callback "NEED_PT_DECOUPLED_RETRY" einzuführen, der das Timeout per Payload übergeben kriegt.

from hbci4java.

guyyst avatar guyyst commented on June 20, 2024
  • Nach meinem Verständnis ist die HKTAN welche hier erstellt wird genau diese "Hat der User zwischenzeitlich bestätigt?" Nachricht. Wie in den Specs beschrieben, hat diese 2. HKTAN beim Decoupled Verfahren ja den Prozess S, und erhält bei noch ausstehender Bestätigung in der HITAN Antwort den Code 3956. Bevor ich irgendwelche Änderungen gemacht habe, war das ja bereits der Ablauf. Mit meinem Change wird lediglich als Reaktion auf den Code 3956 durch diese Zeile in GVTAN2Step.java der selbe HKTAN wiederholt. Also quasi der Zurück-Sprung auf Schritt 2a. Ich dachte nicht, dass dafür eine dedizierte Nachricht erstellt werden müsste, da es ja eigentlich exakt die selbe Abfrage ist. (Und da es bei meinen Tests auch genau so geklappt hat :p).

  • Ich hab einen neuen Commit gemacht, und nach deinem Vorschlag einen NEED_PT_DECOUPLED_RETRY callback hinzugefügt. Beide NEED_PT_DECOUPLED callbacks liefern jetzt auch in retData die erforderliche Sleep Dauer. Das ganze hatte ich vorher dadurch gelöst, dass getMinimumTimeBeforeFirstDecoupledRefresh() und getMinimumTimeBeforeNextDecoupledRefresh() einfach öffentlich waren, und die aufrufenden Anwendung somit bereits die Möglichkeit hatte die Wartezeit zu visualisieren. Aber ich gebe dir Recht, es ist einfacher und sauberer das über retData zu erledigen.

from hbci4java.

willuhn avatar willuhn commented on June 20, 2024
  • Nach meinem Verständnis ist die HKTAN welche hier erstellt wird genau diese "Hat der User zwischenzeitlich bestätigt?" Nachricht.

Korrekt. Aber wie löst du diese HBCI-Nachricht nochmal erneut aus? Erstellst du hierfür in deinem Code nochmal separat ein "GVTAN2Step", das du dann manuell an die Bank sendest? Das muss ja eine einzelne HBCI-Nachricht sein, die nur genau das enthält.

from hbci4java.

guyyst avatar guyyst commented on June 20, 2024

Ah verstehe, da habe ich mich auf den existierenden Code in HBCIDialog.java verlassen, welcher task.redo() checked, und falls es einen Redo gibt, eine neue Message mit nur diesem redo-job erstellt.

from hbci4java.

willuhn avatar willuhn commented on June 20, 2024

Kannst du vielleicht mal ein Schnipsel des Codes von deiner Seite posten? Ich kann mir immer noch nicht so richtig erklären, wie du die Nachfrage-Nachricht auslöst.

from hbci4java.

guyyst avatar guyyst commented on June 20, 2024

Also mein Verständnis des Ablaufs, durch welchen die Nachfrage-Nachricht wiederholt versandt wird, ist wie folgt:

  1. Die aller erste Status-Nachfrage wird in AbstractPinTanPassport.java mit diesen Zeilen erstellt und der queue hinzugefügt:
final GVTAN2Step hktan2 = (GVTAN2Step) handler.newJob("TAN2Step");
hktan2.setProcess(proc);
hktan2.setExternalId(task.getExternalId()); // externe ID auch an HKTAN2 durchreichen
hktan2.setSegVersion(segversion);
hktan2.setParam("notlasttan","N");

// in dem zweiten HKTAN-Job eine referenz auf den originalen job
// speichern, damit die antwortdaten für den job, die als antwortdaten
// für hktan2 ankommen, dem richtigen job zugeordnet werden können
HBCIUtils.log("storing reference to original job in new HKTAN segment",HBCIUtils.LOG_DEBUG);
hktan2.setTask(task);

// in dem ersten HKTAN-job eine referenz auf den zweiten speichern,
// damit der erste die auftragsreferenz später im zweiten speichern kann
hktan.setStep2(hktan2);

// Dahinter eine neue Nachricht mit dem einzelnen HKTAN#2
HBCIUtils.log("adding new message with HKTAN(p=2) after current one",HBCIUtils.LOG_DEBUG);
HBCIMessage newMsg = queue.insertAfter(message);
newMsg.append(hktan2);
  1. Dann wird in der doJobs() Methode von HBCIDialog.java diese Nachricht versandt, und durch den Aufruf von task.fillJobResult(msgstatus,segnum) in Zeile 311 wird meine Änderung in extractResults() aus GVTAN2Step.java aufgerufen, wo, durch die Zeile this.redo = this; dem Status-Refresh Task gesagt wird, dass er sich selbst wiederholen soll.

  2. Die extractResults() Methode returned, und wir sind wieder in doJobs() von HBCIDialog.java, wo durch diese Zeilen erkannt wird, dass es einen redo-task gibt (unser Status-Nachfrage-Task). Es wird eine neue Nachricht erstellt, der Task angehängt und die Nachricht auf die queue gepackt:

HBCIMessage newMsg = null;
for (HBCIJobImpl task:tasks)
{
    final String name = task.getName();
    if (task.skipped())
    {
        HBCIUtils.log("skipping repeat for task " + name, HBCIUtils.LOG_DEBUG);
        continue;
    }
    HBCIJobImpl redo = task.redo();
    if (redo != null)
    {
        // Nachricht bei Bedarf erstellen und an die Queue haengen
        if (newMsg == null)
        {
            newMsg = new HBCIMessage();
            queue.append(newMsg);
        }
        // Task hinzufuegen
        HBCIUtils.log("repeat task " + redo.getName(),HBCIUtils.LOG_DEBUG);
        newMsg.append(redo);
    }
}
  1. Der while(true) loop in HBCIDialog.java springt wieder nach oben, die Zeile 206 greift unsere eben erstellte Message von der queue und die erneute Nachfrage-Nachricht wird in Zeile 287 abgeschickt:
msg = this.queue.poll();
[...]
msgstatus = k.rawDoIt(msgPassports,HBCIKernelImpl.SIGNIT,HBCIKernelImpl.CRYPTIT,HBCIKernelImpl.NEED_CRYPT);

Vielleicht verstehe ich hier irgendwas falsch, aber mit dem Debugger kann ich diese Schritte alle nachprüfen und die Logs geben den erfolgreich Versand der Nachricht auch wieder.

from hbci4java.

willuhn avatar willuhn commented on June 20, 2024

Ah, jetzt. Ich hatte einfach das "this.redo = this" übersehen. OK, erstaunlich, dass das so funktioniert ;)

Jetzt ist mir noch 1 Sache aufgefallen: Ich würde das Warten in HBCIPassportPinTan (Zeile 407ff) ersatzlos streichen. Grund: Das ist ja der erste Callback für die PushTAN. Zu dem Zeitpunkt ist noch nicht bekannt, ob überhaupt ein Retry notwendig sein wird. Das wissen wir erst, wenn das erste 3956 als Response eintrifft. Das ist in GVTAN2Step. Und dort wird ja dann auch gewartet (entweder direkt im Callback durch den Nutzer der API oder im Anschluss mit dem Thread.sleep). Das Sleep in HBCIPassportPinTan ist da aus meiner Sicht überflüssig.

from hbci4java.

guyyst avatar guyyst commented on June 20, 2024

Bei dem Warten in HBCIPassportPinTan.java war ich mir auch erst nicht sicher, aber ich glaube schon, dass das der Spezifikation entspricht. Wenn wir in Schritt 1b diese Nachricht von der Bank bekommen: 3955::Auftrag empfangen - Bitte Auftrag in Ihrer App freigeben erfolgt danach in Schritt 2a ja die aller erste Statusabfrage (bei uns die aus HBCIPassportPinTan.java). Diese wird immer notwendig sein.

Nachdem diese Statusabfrage eingereicht wurde, und wir daraufhin ein 3956 erhalten, erfolgt dann das erste Retry. Aber die Tatsache, dass es in den BPDs sowohl decoupled_time_before_next_status_request, als auch decoupled_time_before_first_status_request gibt, lässt mich vermuten, dass wir auch vor der aller ersten Statusabfrage (also die, welche in HBCIPassportPinTan.java erstellt wird) warten müssen.

from hbci4java.

willuhn avatar willuhn commented on June 20, 2024

Das glaube ich nicht. Bisher habe ich es in Hibiscus ja auch komplett ohne Retry umgesetzt und ich beachte da auch die Retry-Zeiten nicht. Einfach deshalb, weil es da gar keinen Status-Request sondern nur die initiale PushTAN-Abfrage. Also User kriegt den TAN-Dialog in der App angezeigt, bestätigt in der App und danach in Hibiscus. Fertig. HKTAN wird eingereicht und die Bank genehmigt den Auftrag. Genau wie bisher bei allen anderen TAN-Verfahren auch. Nur eben, dass das HKTAN keine TAN mehr enthält. Soweit ist es in HBCIPassportPinTan umgesetzt.

Die Prozessergänzung für die Retries kommt erst danach in's Spiel, falls der User in den Callbackl bestätigt hat, obwohl er in der App noch nicht freigegeben hat. Nur in dem Fall ist das Retry ja überhaupt nötig. Und erst dann muss gewartet werden. Also erst dann, wenn ein erneutes HKTAN an die Bank gesendet werden soll.

from hbci4java.

guyyst avatar guyyst commented on June 20, 2024

Würdest du dann aber sagen, dass in GVTAN2Step.java beim ersten Retry decoupled_time_before_first_status_request gewartet, und bei allen weiteren decoupled_time_before_next_status_request gewartet wird? Oder würde decoupled_time_before_first_status_request dann komplett wegfallen? (Abgesehen davon, dass die Werte bei mir bisher immer beide 1 Sekunde waren.)

from hbci4java.

willuhn avatar willuhn commented on June 20, 2024

Ja, so sollte es aus meiner Sicht implementiert sein. Beim ersten Retry decoupled_time_before_first_status_request alle folgenden decoupled_time_before_next_status_request. ich glaube allerdings nicht, dass es eine Bank gibt, die dort unterschiedliche Werte verwendet. Und wie bei deiner Bank werden die meisten Banken überhaupt keine relevanten Wartezeiten liefern.

Ich denke, man könnte einfach pauschal decoupled_time_before_next_status_request verwenden - auch für den ersten.

from hbci4java.

Related Issues (20)

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.