-
Notifications
You must be signed in to change notification settings - Fork 50
/
Copy pathUmsatzAbrufPinTan.java
437 lines (365 loc) · 16.1 KB
/
UmsatzAbrufPinTan.java
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
package org.kapott.hbci.examples;
import java.io.File;
import java.util.Date;
import java.util.List;
import java.util.Properties;
import org.kapott.hbci.GV.HBCIJob;
import org.kapott.hbci.GV_Result.GVRKUms;
import org.kapott.hbci.GV_Result.GVRKUms.UmsLine;
import org.kapott.hbci.GV_Result.GVRSaldoReq;
import org.kapott.hbci.callback.AbstractHBCICallback;
import org.kapott.hbci.exceptions.HBCI_Exception;
import org.kapott.hbci.manager.BankInfo;
import org.kapott.hbci.manager.HBCIHandler;
import org.kapott.hbci.manager.HBCIUtils;
import org.kapott.hbci.manager.HBCIVersion;
import org.kapott.hbci.passport.AbstractHBCIPassport;
import org.kapott.hbci.passport.HBCIPassport;
import org.kapott.hbci.status.HBCIExecStatus;
import org.kapott.hbci.structures.Konto;
import org.kapott.hbci.structures.Value;
/**
* Demo zum Abruf von Umsaetzen per PIN/TAN-Verfahren.
*
* Die folgende Demo zeigt mit dem minimal noetigen Code, wie eine Umsatz-Abfrage
* fuer ein Konto durchgefuehrt werden kann. Hierzu wird der Einfachheit halber
* das Verfahren PIN/TAN verwendet, da es von den meisten Banken unterstuetzt wird.
*
* Trage vor dem Ausfuehren des Programms die Zugangsdaten zu deinem Konto ein.
*/
public class UmsatzAbrufPinTan
{
/**
* Die BLZ deiner Bank.
*/
private final static String BLZ = "12345678";
/**
* Deine Benutzerkennung.
*/
private final static String USER = "1234567890";
/**
* Deine PIN.
*/
private final static String PIN = "12345";
/**
* Die zu verwendende HBCI-Version.
*/
private final static HBCIVersion VERSION = HBCIVersion.HBCI_300;
/**
* Main-Methode.
* @param args
* @throws Exception
*/
public static void main(String[] args) throws Exception
{
// HBCI4Java initialisieren
// In "props" koennen optional Kernel-Parameter abgelegt werden, die in der Klasse
// org.kapott.hbci.manager.HBCIUtils (oben im Javadoc) beschrieben sind.
Properties props = new Properties();
HBCIUtils.init(props,new MyHBCICallback());
// In der Passport-Datei speichert HBCI4Java die Daten des Bankzugangs (Bankparameterdaten, Benutzer-Parameter, etc.).
// Die Datei kann problemlos geloescht werden. Sie wird beim naechsten mal automatisch neu erzeugt,
// wenn der Parameter "client.passport.PinTan.init" den Wert "1" hat (siehe unten).
// Wir speichern die Datei der Einfachheit halber im aktuellen Verzeichnis.
final File passportFile = new File("testpassport.dat");
// Wir setzen die Kernel-Parameter zur Laufzeit. Wir koennten sie alternativ
// auch oben in "props" setzen.
HBCIUtils.setParam("client.passport.default","PinTan"); // Legt als Verfahren PIN/TAN fest.
HBCIUtils.setParam("client.passport.PinTan.init","1"); // Stellt sicher, dass der Passport initialisiert wird
// Erzeugen des Passport-Objektes.
HBCIPassport passport = AbstractHBCIPassport.getInstance(passportFile);
// Konfigurieren des Passport-Objektes.
// Das kann alternativ auch alles ueber den Callback unten geschehen
// Das Land.
passport.setCountry("DE");
// Server-Adresse angeben. Koennen wir entweder manuell eintragen oder direkt von HBCI4Java ermitteln lassen
BankInfo info = HBCIUtils.getBankInfo(BLZ);
passport.setHost(info.getPinTanAddress());
// TCP-Port des Servers. Bei PIN/TAN immer 443, da das ja ueber HTTPS laeuft.
passport.setPort(443);
// Art der Nachrichten-Codierung. Bei Chipkarte/Schluesseldatei wird
// "None" verwendet. Bei PIN/TAN kommt "Base64" zum Einsatz.
passport.setFilterType("Base64");
// Das Handle ist die eigentliche HBCI-Verbindung zum Server
HBCIHandler handle = null;
try
{
// Verbindung zum Server aufbauen
handle = new HBCIHandler(VERSION.getId(),passport);
// Wir verwenden einfach das erste Konto, welches wir zur Benutzerkennung finden
Konto[] konten = passport.getAccounts();
if (konten == null || konten.length == 0)
error("Keine Konten ermittelbar");
log("Anzahl Konten: " + konten.length);
Konto k = konten[0];
// 1. Auftrag fuer das Abrufen des Saldos erzeugen
HBCIJob saldoJob = handle.newJob("SaldoReq");
saldoJob.setParam("my",k); // festlegen, welches Konto abgefragt werden soll.
saldoJob.addToQueue(); // Zur Liste der auszufuehrenden Auftraege hinzufuegen
// 2. Auftrag fuer das Abrufen der Umsaetze erzeugen
HBCIJob umsatzJob = handle.newJob("KUmsAll");
umsatzJob.setParam("my",k); // festlegen, welches Konto abgefragt werden soll.
umsatzJob.addToQueue(); // Zur Liste der auszufuehrenden Auftraege hinzufuegen
// Hier koennen jetzt noch weitere Auftraege fuer diesen Bankzugang hinzugefuegt
// werden. Z.Bsp. Ueberweisungen.
// Alle Auftraege aus der Liste ausfuehren.
HBCIExecStatus status = handle.execute();
// Pruefen, ob die Kommunikation mit der Bank grundsaetzlich geklappt hat
if (!status.isOK())
error(status.toString());
// Auswertung des Saldo-Abrufs.
GVRSaldoReq saldoResult = (GVRSaldoReq) saldoJob.getJobResult();
if (!saldoResult.isOK())
error(saldoResult.toString());
Value s = saldoResult.getEntries()[0].ready.value;
log("Saldo: " + s.toString());
// Das Ergebnis des Jobs koennen wir auf "GVRKUms" casten. Jobs des Typs "KUmsAll"
// liefern immer diesen Typ.
GVRKUms result = (GVRKUms) umsatzJob.getJobResult();
// Pruefen, ob der Abruf der Umsaetze geklappt hat
if (!result.isOK())
error(result.toString());
// Alle Umsatzbuchungen ausgeben
List<UmsLine> buchungen = result.getFlatData();
for (UmsLine buchung:buchungen)
{
StringBuilder sb = new StringBuilder();
sb.append(buchung.valuta);
Value v = buchung.value;
if (v != null)
{
sb.append(": ");
sb.append(v);
}
List<String> zweck = buchung.usage;
if (zweck != null && zweck.size() > 0)
{
sb.append(" - ");
// Die erste Zeile des Verwendungszwecks ausgeben
sb.append(zweck.get(0));
}
// Ausgeben der Umsatz-Zeile
log(sb.toString());
}
}
finally
{
// Sicherstellen, dass sowohl Passport als auch Handle nach Beendigung geschlossen werden.
if (handle !=null)
handle.close();
if (passport != null)
passport.close();
}
}
/**
* Ueber diesen Callback kommuniziert HBCI4Java mit dem Benutzer und fragt die benoetigten
* Informationen wie Benutzerkennung, PIN usw. ab.
*/
private static class MyHBCICallback extends AbstractHBCICallback
{
/**
* @see org.kapott.hbci.callback.HBCICallback#log(java.lang.String, int, java.util.Date, java.lang.StackTraceElement)
*/
@Override
public void log(String msg, int level, Date date, StackTraceElement trace)
{
// Ausgabe von Log-Meldungen bei Bedarf
// System.out.println(msg);
}
/**
* @see org.kapott.hbci.callback.HBCICallback#callback(org.kapott.hbci.passport.HBCIPassport, int, java.lang.String, int, java.lang.StringBuffer)
*/
@Override
public void callback(HBCIPassport passport, int reason, String msg, int datatype, StringBuffer retData)
{
// Diese Funktion ist wichtig. Ueber die fragt HBCI4Java die benoetigten Daten von uns ab.
switch (reason)
{
// Mit dem Passwort verschluesselt HBCI4Java die Passport-Datei.
// Wir nehmen hier der Einfachheit halber direkt die PIN. In der Praxis
// sollte hier aber ein staerkeres Passwort genutzt werden.
// Die Ergebnis-Daten muessen in dem StringBuffer "retData" platziert werden.
case NEED_PASSPHRASE_LOAD:
case NEED_PASSPHRASE_SAVE:
retData.replace(0,retData.length(),PIN);
break;
// PIN wird benoetigt
case NEED_PT_PIN:
retData.replace(0,retData.length(),PIN);
break;
// BLZ wird benoetigt
case NEED_BLZ:
retData.replace(0,retData.length(),BLZ);
break;
// Die Benutzerkennung
case NEED_USERID:
retData.replace(0,retData.length(),USER);
break;
// Die Kundenkennung. Meist identisch mit der Benutzerkennung.
// Bei manchen Banken kann man die auch leer lassen
case NEED_CUSTOMERID:
retData.replace(0,retData.length(),USER);
break;
////////////////////////////////////////////////////////////////////////
// Die folgenden Callbacks sind nur fuer die Ausfuehrung TAN-pflichtiger
// Geschaeftsvorfaelle bei der Verwendung des PIN/TAN-Verfahrens noetig.
// Z.Bsp. beim Versand einer Ueberweisung
// "NEED_PT_SECMECH" kann jedoch auch bereits vorher auftreten.
// HBCI4Java benoetigt die TAN per PhotoTAN-Verfahren
// Liefert die anzuzeigende PhotoTAN-Grafik, die mit der entsprechenden
// Smartphone-App der Bank fotografiert werden muss, um die TAN
// zu generieren. Eine Implementierung muss diese Grafik anzeigen
// sowie ein Eingabefeld fuer die TAN. Der Callback muss dann die vom
// User eingegebene TAN zurueckliefern (nachdem dieser die Grafik
// fotografiert und die App ihm die TAN angezeigt hat)
case NEED_PT_PHOTOTAN:
// Die Klasse "MatrixCode" kann zum Parsen der Daten verwendet werden
try
{
// MatrixCode code = new MatrixCode(retData.toString());
// Liefert den Mime-Type der grafik (i.d.R. "image/png").
// String type = code.getMimetype();
// Der Stream enthaelt jetzt die Binaer-Daten des Bildes
// InputStream stream = new ByteArrayInputStream(code.getImage());
// .... Hier Dialog mit der Grafik anzeigen und User-Eingabe der TAN
// Die Variable "msg" aus der Methoden-Signatur enthaelt uebrigens
// den bankspezifischen Text mit den Instruktionen fuer den User.
// Der Text aus "msg" sollte daher im Dialog dem User angezeigt
// werden.
String tan = null;
retData.replace(0,retData.length(),tan);
}
catch (Exception e)
{
throw new HBCI_Exception(e);
}
break;
case NEED_PT_QRTAN:
// Die Klasse "QRCode" kann zum Parsen der Daten verwendet werden
try
{
// QRCode code = new QRCode(retData.toString(),msg);
// Der Stream enthaelt jetzt die Binaer-Daten des Bildes
// InputStream stream = new ByteArrayInputStream(code.getImage());
// .... Hier Dialog mit der Grafik anzeigen und User-Eingabe der TAN
// Die Variable "msg" aus der Methoden-Signatur enthaelt uebrigens
// den bankspezifischen Text mit den Instruktionen fuer den User.
// Der Text aus "msg" sollte daher im Dialog dem User angezeigt
// werden. Da Sparkassen den eigentlichen Bild u.U. auch in msg verpacken,
// sollte zur Anzeige nicht der originale Text verwendet werden sondern
// der von QRCode - dort ist dann die ggf. enthaltene Base64-codierte QR-Grafik entfernt
// msg = code.getMessage();
String tan = null;
retData.replace(0,retData.length(),tan);
}
catch (Exception e)
{
throw new HBCI_Exception(e);
}
break;
// HBCI4Java benoetigt den Code des verwendenden TAN-Verfahren (smsTAN,
// chipTAN optisch, photoTAN,...)
// I.d.R. ist das eine dreistellige mit "9" beginnende Ziffer
case NEED_PT_SECMECH:
// Als Parameter werden die verfuegbaren TAN-Verfahren uebergeben.
// Der Aufbau des String ist wie folgt:
// <code1>:<name1>|<code2>:<name2>|...
// Bsp:
// 911:smsTAN|920:chipTAN optisch|955:photoTAN
// String options = retData.toString();
// Der Callback muss den Code des zu verwendenden TAN-Verfahrens
// zurueckliefern
// In "code" muss der 3-stellige Code des vom User gemaess obigen
// Optionen ausgewaehlte Verfahren eingetragen werden
String code = "";
retData.replace(0,retData.length(),code);
break;
// HBCI4Java benoetigt die TAN per smsTAN/chipTAN/weiteren TAN-Verfahren
case NEED_PT_TAN:
// Wenn per "retData" Daten uebergeben wurden, dann enthalten diese
// den fuer chipTAN optisch zu verwendenden Flickercode.
// Falls nicht, ist es eine TAN-Abfrage, fuer die keine weiteren
// Parameter benoetigt werden (z.Bsp. beim smsTAN-Verfahren)
// Die Variable "msg" aus der Methoden-Signatur enthaelt uebrigens
// den bankspezifischen Text mit den Instruktionen fuer den User.
// Der Text aus "msg" sollte daher im Dialog dem User angezeigt
// werden.
String flicker = retData.toString();
if (flicker != null && flicker.length() > 0)
{
// Ist chipTAN optisch. Es muss ein animierter Barcode angezeigt
// werden. Hierfuer kann die Hilfsklasse "FlickerRenderer" verwendet
// werden. Diese enthalt bereits das Parsen. Es muss lediglich die
// Methode "paint" ueberschrieben werden.
// FlickerRenderer renderer = new FlickerRenderer(flicker);
// Hier TAN-Abfrage mit dem animierten Barcode anzeigen sowie
// Eingabefeld fuer die TAN
String tan = null;
retData.replace(0,retData.length(),tan);
}
else
{
// Ist smsTAN, iTAN, o.ae.
// Dialog zur TAN-Eingabe anzeigen mit dem Text aus "msg".
String tan = null;
retData.replace(0,retData.length(),tan);
}
break;
// Beim Verfahren smsTAN ist es moeglich, mehrere Handynummern mit
// Aliasnamen bei der Bank zu hinterlegen. Auch wenn nur eine Handy-
// Nummer bei der Bank hinterlegt ist, kann es durchaus passieren,
// dass die Bank dennoch die Aufforderung zur Auswahl des TAN-Mediums
// sendet.
case NEED_PT_TANMEDIA:
// Als Parameter werden die verfuegbaren TAN-Medien uebergeben.
// Der Aufbau des String ist wie folgt:
// <name1>|<name2>|...
// Bsp:
// Privathandy|Firmenhandy
// String options = retData.toString();
// Der Callback muss den vom User ausgewaehlten Aliasnamen
// zurueckliefern. Falls "options" kein "|" enthaelt, ist davon
// auszugehen, dass nur eine moegliche Option existiert. In dem
// Fall ist keine Auswahl noetig und "retData" kann unveraendert
// bleiben
String alias = null;
retData.replace(0,retData.length(),alias);
break;
//
////////////////////////////////////////////////////////////////////////
// Manche Fehlermeldungen werden hier ausgegeben
case HAVE_ERROR:
UmsatzAbrufPinTan.log(msg);
break;
default:
// Wir brauchen nicht alle der Callbacks
break;
}
}
/**
* @see org.kapott.hbci.callback.HBCICallback#status(org.kapott.hbci.passport.HBCIPassport, int, java.lang.Object[])
*/
@Override
public void status(HBCIPassport passport, int statusTag, Object[] o)
{
// So aehnlich wie log(String,int,Date,StackTraceElement) jedoch fuer Status-Meldungen.
}
}
/**
* Gibt die angegebene Meldung aus.
* @param msg die Meldung.
*/
private static void log(String msg)
{
System.out.println(msg);
}
/**
* Beendet das Programm mit der angegebenen Fehler-Meldung.
* @param msg die Meldung.
*/
private static void error(String msg)
{
System.err.println(msg);
System.exit(1);
}
}