Skip to content
This repository has been archived by the owner on Jan 28, 2022. It is now read-only.

Commit

Permalink
Chipcard now working. Added examples so that the people don't need to…
Browse files Browse the repository at this point in the history
… figure out by them own how to do these things.
  • Loading branch information
monofox committed Dec 5, 2018
1 parent 2b0b012 commit e8a6215
Show file tree
Hide file tree
Showing 11 changed files with 370 additions and 14 deletions.
4 changes: 3 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -52,9 +52,11 @@ Implemented is: `nationalTransfer` and `sepaTransfer`.

Furthermore if you're doing some transfer you're partially asked to enter three times the password. Now you can build your PIN cache with help of the `set_callbackPasswordStatus` function. This calls the python callback with parameters `token`, `pin` and `status` whereas the status field can be 9 = reset, 1 = Bad password, 2 = Remove password and 0 = all went fine.

You can find some examples inside of the `examples/` folder.

Known Bugs/Missing features
===========================
Right now, this extension does not support the Smartcard/Chipcard procedure for authentication. This is planned for the future, but will need time in order to write the corresponding backend.
Smartcard/Chipcard support meanwhile integrated. But no "text" that user has to enter something on the readers panel is provided.

The server certificate of the HTTPS connection is not validated at the moment, so do not use it for sensitive data, as man in the middle attack is possible without notice.

23 changes: 14 additions & 9 deletions aqbanking/aqbanking.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -659,6 +659,7 @@ static PyObject *aqbanking_Account_balance(aqbanking_Account* self, PyObject *ar
double balance;
const char *bank_code;
const char *account_no;
PyObject *currency;

// Check if all necessary data in account object is given!
if (self->no == NULL)
Expand Down Expand Up @@ -708,19 +709,23 @@ static PyObject *aqbanking_Account_balance(aqbanking_Account* self, PyObject *ar
job = AB_JobGetBalance_new(a);
AB_Job_List2_PushBack(jl, job);
rv = AB_Banking_ExecuteJobs(self->ab, jl, ctx);

if (rv)
if (rv > 0)
{
PyErr_SetString(ExecutionFailed, "Could not get the balance!");
return NULL;
}

// With success. No process the result.
ai = AB_ImExporterContext_GetFirstAccountInfo (ctx);
status = AB_ImExporterAccountInfo_GetFirstAccountStatus (ai);
bal = AB_AccountStatus_GetBookedBalance (status);
v = AB_Balance_GetValue (bal);
ai = AB_ImExporterContext_GetFirstAccountInfo(ctx);
if (ai == NULL) {
PyErr_SetString(ExecutionFailed, "Could not retrieve balance.");
return NULL;
}
status = AB_ImExporterAccountInfo_GetFirstAccountStatus(ai);
bal = AB_AccountStatus_GetBookedBalance(status);
v = AB_Balance_GetValue(bal);
balance = AB_Value_GetValueAsDouble(v);
currency = PyUnicode_FromString(AB_Value_GetCurrency(v));

// Free jobs.
AB_Job_List2_free(jl);
Expand All @@ -730,11 +735,11 @@ static PyObject *aqbanking_Account_balance(aqbanking_Account* self, PyObject *ar
rv = AB_free(self);
if (rv > 0)
{
PyErr_SetString(ExecutionFailed, "Could not free up aqbanking.");
return NULL;
}

// FIXME: currency!
return Py_BuildValue("(d,s)", balance, "EUR");
return Py_BuildValue("(d,O)", balance, currency);
}

static PyObject *aqbanking_Account_available_jobs(aqbanking_Account* self, PyObject *args, PyObject *keywds)
Expand Down Expand Up @@ -1066,7 +1071,7 @@ static PyObject *aqbanking_Account_transactions(aqbanking_Account* self, PyObjec
}

trans->value = PyFloat_FromDouble(AB_Value_GetValueAsDouble(v));
trans->currency = PyUnicode_FromString("EUR");
trans->currency = PyUnicode_FromString(AB_Value_GetCurrency(v));
trans->uniqueId = PyLong_FromLong(AB_Transaction_GetUniqueId(t));
if (AB_Transaction_GetTransactionText(t) == NULL) {
trans->transactionText = PyUnicode_FromString("");
Expand Down
100 changes: 100 additions & 0 deletions aqbanking/pyaqhandler.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -5,18 +5,118 @@
#include <gwenhywfar/version.h>
#include <gwenhywfar/cgui.h>
#include <gwenhywfar/gui_be.h>
#include <gwenhywfar/debug.h>
#include <gwen-gui-cpp/cppdialog.hpp>
#include <gwen-gui-cpp/cppwidget.hpp>
#include "pyaqhandler.hpp"

PyAqHandler::PyAqHandler() : CppGui()
{
GWEN_Logger_SetLevel(0, GWEN_LoggerLevel_Verbous);
GWEN_Gui_SetGui(this->_gui);
GWEN_Gui_AddFlags(_gui, GWEN_GUI_FLAGS_DIALOGSUPPORTED);
GWEN_Gui_SetName(_gui, "pyaq-gui");
this->callbackLog = NULL;
this->callbackPassword = NULL;
this->callbackCheckCert = NULL;
this->callbackPasswordStatus = NULL;
}

int PyAqHandler::setupDialog(GWEN_WIDGET *w) {
CppWidget *xw=NULL;
printf("GWEN Dialog Widget: %d (%s)\n\n",
GWEN_Widget_GetType(w),
GWEN_Widget_Type_toString(GWEN_Widget_GetType(w)));


switch(GWEN_Widget_GetType(w)) {
case GWEN_Widget_TypeLabel:
xw = new CppWidget(w);
const char *s;
const char *name;
name=xw->getName();
s=xw->getText(0);
printf("Got text in label %s: %s\n", name, s);
break;
case GWEN_Widget_TypeDialog:
case GWEN_Widget_TypeVLayout:
case GWEN_Widget_TypeHLayout:
case GWEN_Widget_TypeGridLayout:
case GWEN_Widget_TypeLineEdit:
case GWEN_Widget_TypeVSpacer:
case GWEN_Widget_TypeHSpacer:
case GWEN_Widget_TypePushButton:
case GWEN_Widget_TypeHLine:
case GWEN_Widget_TypeVLine:
case GWEN_Widget_TypeTextEdit:
case GWEN_Widget_TypeComboBox:
case GWEN_Widget_TypeTabBook:
case GWEN_Widget_TypeTabPage:
case GWEN_Widget_TypeCheckBox:
case GWEN_Widget_TypeGroupBox:
case GWEN_Widget_TypeWidgetStack:
case GWEN_Widget_TypeTextBrowser:
case GWEN_Widget_TypeScrollArea:
case GWEN_Widget_TypeProgressBar:
case GWEN_Widget_TypeListBox:
case GWEN_Widget_TypeRadioButton:
case GWEN_Widget_TypeSpinBox:
default:
DBG_ERROR(GWEN_LOGDOMAIN, "Unhandled widget type %d (%s)",
GWEN_Widget_GetType(w), GWEN_Widget_Type_toString(GWEN_Widget_GetType(w)));
break;
}

GWEN_WIDGET *wChild;
wChild=GWEN_Widget_Tree_GetFirstChild(w);
while(wChild) {
setupDialog(wChild);
wChild=GWEN_Widget_Tree_GetNext(wChild);
}

return 0;
}

int PyAqHandler::openDialog(GWEN_DIALOG *dlg, uint32_t guiid) {
printf("PyAqHandler::OpenDialog\n");
// Finally this should be passed sometime to python.
// For now we need also to extract data.
CppDialog *cppDlg = new CppDialog(dlg);
GWEN_DIALOG *gwd = cppDlg->getCInterface();
GWEN_WIDGET *w;
GWEN_WIDGET_TREE *wtree = GWEN_Dialog_GetWidgets(gwd);
// We need a tree
if (wtree==NULL) {
DBG_ERROR(GWEN_LOGDOMAIN, "No widget tree in dialog");
return GWEN_ERROR_GENERIC;
}

// First child.
w=GWEN_Widget_Tree_GetFirst(wtree);
if (w==NULL) {
DBG_ERROR(GWEN_LOGDOMAIN, "No widgets in dialog");
return GWEN_ERROR_GENERIC;
}
printf("GWEN Dialog Widget: %d (%s)\n\n",
GWEN_Widget_GetType(w),
GWEN_Widget_Type_toString(GWEN_Widget_GetType(w)));

w=GWEN_Widget_Tree_GetFirstChild(w);
while(w) {
setupDialog(w);
w=GWEN_Widget_Tree_GetNext(w);
}

return 0;
}



int PyAqHandler::closeDialog(GWEN_DIALOG *dlg) {
printf("PyAqHandler::CloseDialog\n");
return 0;
}

int PyAqHandler::setPasswordStatus(const char *token, const char *pin,
GWEN_GUI_PASSWORD_STATUS status, uint32_t guiid) {
int pystat = 0;
Expand Down
4 changes: 4 additions & 0 deletions aqbanking/pyaqhandler.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ static PyObject *AqBankingDeInitializeError;
* This handles all request and so it also gives the opportunity to have handlers per account!
*/
class PyAqHandler : public CppGui {

public:
PyAqHandler();

Expand All @@ -30,6 +31,9 @@ class PyAqHandler : public CppGui {
virtual int getPassword(uint32_t flags, const char *token, const char *title, const char *text, char *buffer, int minLen, int maxLen, uint32_t guiid);
virtual int checkCert(const GWEN_SSLCERTDESCR *cd, GWEN_SYNCIO *sio, uint32_t guiid);
virtual int setPasswordStatus(const char *token, const char *pin, GWEN_GUI_PASSWORD_STATUS status, uint32_t guiid);
virtual int setupDialog(GWEN_WIDGET *w);
virtual int openDialog(GWEN_DIALOG *dlg, uint32_t guiid);
virtual int closeDialog(GWEN_DIALOG *dlg);
};

#endif /* PYAQHANDLER_HPP */
3 changes: 3 additions & 0 deletions examples/chkiban.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
import aqbanking
d = aqbanking.chkiban('<iban>')
print(d)
50 changes: 50 additions & 0 deletions examples/getbalance.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
#!/usr/bin/env python
# -*- coding: utf-8 -*-

import aqbanking
import getpass

cachedPasswords = {}

def callback(domain, prio, msg):
print('[LOG]: %r' % (msg,))

# const char *token, const char *pin, GWEN_GUI_PASSWORD_STATUS enumStatus, uint32_t guiid
# 0 = OK
# 1 = Bad
# 2 = Remove
# 4 = Used
# 8 = Unused
# 16 = Unknown
def passwordStatus_cb(token, pin, status):
print('cb_pw_status: %s / <pin censored> / %d' % (token, status))
if status == 2 or status == 1:
try:
del(cachedPasswords[token])
except:
pass
elif status == 0:
cachedPasswords[token] = pin

def password_cb(flags, token, title, text, minLen, maxLen):
# Ask only, if we didn't asked already for a PIN.
try:
return cachedPasswords[token]
except:
plainText = text if '<html>' not in text else text[:text.find('<html>')].replace('\r', '').replace('\n', '')
pin = getpass.getpass('%s: ' % (plainText,))
return pin

for f in aqbanking.listacc():
print('Available configured banks: ', f.bank_name)

acc = aqbanking.Account(no='100254687', bank_code='35468754')
acc.set_callbackLog(callback)
acc.set_callbackPassword(password_cb)
acc.set_callbackPasswordStatus(passwordStatus_cb)
ret = acc.balance()
if ret is not None:
try:
print(ret[0], ' ', ret[1])
except TypeError:
pass
47 changes: 47 additions & 0 deletions examples/getjobs.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
#!/usr/bin/env python
# -*- coding: utf-8 -*-

import aqbanking
import getpass

cachedPasswords = {}

def callback(domain, prio, msg):
print('[LOG]: %r' % (msg,))

# const char *token, const char *pin, GWEN_GUI_PASSWORD_STATUS enumStatus, uint32_t guiid
# 0 = OK
# 1 = Bad
# 2 = Remove
# 4 = Used
# 8 = Unused
# 16 = Unknown
def passwordStatus_cb(token, pin, status):
print('cb_pw_status: %s / <pin censored> / %d' % (token, status))
if status == 2 or status == 1:
try:
del(cachedPasswords[token])
except:
pass
elif status == 0:
cachedPasswords[token] = pin

def password_cb(flags, token, title, text, minLen, maxLen):
# Ask only, if we didn't asked already for a PIN.
try:
return cachedPasswords[token]
except:
plainText = text if '<html>' not in text else text[:text.find('<html>')].replace('\r', '').replace('\n', '')
pin = getpass.getpass('%s: ' % (plainText,))
return pin

acc = aqbanking.Account(no='100254687', bank_code='35468754')
acc.set_callbackLog(callback)
acc.set_callbackPassword(password_cb)
acc.set_callbackPasswordStatus(passwordStatus_cb)
ret = acc.availableJobs()
if ret is not None:
try:
print(ret[0])
except TypeError:
pass
44 changes: 44 additions & 0 deletions examples/listaccs.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
#!/usr/bin/env python
# -*- coding: utf-8 -*-

import aqbanking
import getpass

cachedPasswords = {}

def callback(domain, prio, msg):
print('[LOG]: %r' % (msg,))

# const char *token, const char *pin, GWEN_GUI_PASSWORD_STATUS enumStatus, uint32_t guiid
# 0 = OK
# 1 = Bad
# 2 = Remove
# 4 = Used
# 8 = Unused
# 16 = Unknown
def passwordStatus_cb(token, pin, status):
print('cb_pw_status: %s / <pin censored> / %d' % (token, status))
if status == 2 or status == 1:
try:
del(cachedPasswords[token])
except:
pass
elif status == 0:
cachedPasswords[token] = pin

def password_cb(flags, token, title, text, minLen, maxLen):
# Ask only, if we didn't asked already for a PIN.
try:
return cachedPasswords[token]
except:
plainText = text if '<html>' not in text else text[:text.find('<html>')].replace('\r', '').replace('\n', '')
pin = getpass.getpass('%s: ' % (plainText,))
return pin

accs = aqbanking.listacc()
print(accs)
# you can then access directly the account and can continue on it...
acc = accs[0]
acc.set_callbackLog(callback)
acc.set_callbackPassword(password_cb)
acc.set_callbackPasswordStatus(passwordStatus_cb)
Loading

0 comments on commit e8a6215

Please sign in to comment.