Restructured the complete code to make it more modular
git-svn-id: https://vsmartcard.svn.sourceforge.net/svnroot/vsmartcard@232 96b47cad-a561-4643-ad3b-153ac7d7599c
This commit is contained in:
1
eID_gui/AUTHORS
Normal file
1
eID_gui/AUTHORS
Normal file
@@ -0,0 +1 @@
|
|||||||
|
Dominik Oepen <oepen@informatik.hu-berlin.de>
|
||||||
1
eID_gui/COPYING
Symbolic link
1
eID_gui/COPYING
Symbolic link
@@ -0,0 +1 @@
|
|||||||
|
/usr/share/automake-1.11/COPYING
|
||||||
8
eID_gui/ChangeLog
Normal file
8
eID_gui/ChangeLog
Normal file
@@ -0,0 +1,8 @@
|
|||||||
|
2010-07-01 11:26 frankmorgner
|
||||||
|
|
||||||
|
* .: added ChangeLog for distribution package
|
||||||
|
|
||||||
|
2010-06-08 07:26 oepen
|
||||||
|
|
||||||
|
* .: Working on autotools scripts
|
||||||
|
|
||||||
1
eID_gui/INSTALL
Symbolic link
1
eID_gui/INSTALL
Symbolic link
@@ -0,0 +1 @@
|
|||||||
|
/usr/share/automake-1.11/INSTALL
|
||||||
1
eID_gui/Makefile.am
Normal file
1
eID_gui/Makefile.am
Normal file
@@ -0,0 +1 @@
|
|||||||
|
SUBDIRS = src images
|
||||||
0
eID_gui/NEWS
Normal file
0
eID_gui/NEWS
Normal file
0
eID_gui/README
Normal file
0
eID_gui/README
Normal file
31
eID_gui/configure.ac
Normal file
31
eID_gui/configure.ac
Normal file
@@ -0,0 +1,31 @@
|
|||||||
|
# -*- Autoconf -*-
|
||||||
|
# Process this file with autoconf to produce a configure script.
|
||||||
|
|
||||||
|
AC_PREREQ([2.64])
|
||||||
|
AC_INIT(eid_gui, 0.2, oepen@informatik.hu-berlin.de)
|
||||||
|
AM_INIT_AUTOMAKE
|
||||||
|
AC_CONFIG_MACRO_DIR([m4])
|
||||||
|
|
||||||
|
# Checks for programs.
|
||||||
|
AC_PROG_INSTALL
|
||||||
|
AC_PROG_LN_S
|
||||||
|
AM_PATH_PYTHON
|
||||||
|
|
||||||
|
# Checks for libraries.
|
||||||
|
PKG_CHECK_MODULES(PYGTK, pygtk-2.0)
|
||||||
|
AC_SUBST(PYGTK_CFLAGS)
|
||||||
|
AC_SUBST(PYGTK_LIBS)
|
||||||
|
|
||||||
|
# Checks for header files.
|
||||||
|
|
||||||
|
# Checks for typedefs, structures, and compiler characteristics.
|
||||||
|
|
||||||
|
# Checks for library functions.
|
||||||
|
|
||||||
|
AC_CONFIG_FILES([Makefile
|
||||||
|
src/Makefile
|
||||||
|
src/pace-gui.desktop
|
||||||
|
src/eid/Makefile
|
||||||
|
src/eid/eid_gui_globals.py
|
||||||
|
images/Makefile])
|
||||||
|
AC_OUTPUT
|
||||||
10
eID_gui/images/Makefile.am
Normal file
10
eID_gui/images/Makefile.am
Normal file
@@ -0,0 +1,10 @@
|
|||||||
|
pixmapsdir = $(datadir)/pace-gui/
|
||||||
|
pixmaps_DATA = \
|
||||||
|
OpenPACElogo.png \
|
||||||
|
apply.png \
|
||||||
|
error.png \
|
||||||
|
wait.gif \
|
||||||
|
info.png
|
||||||
|
|
||||||
|
EXTRA_DIST = \
|
||||||
|
$(pixmaps_DATA)
|
||||||
BIN
eID_gui/images/OpenPACElogo.png
Normal file
BIN
eID_gui/images/OpenPACElogo.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 31 KiB |
BIN
eID_gui/images/apply.png
Normal file
BIN
eID_gui/images/apply.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 3.6 KiB |
BIN
eID_gui/images/error.png
Normal file
BIN
eID_gui/images/error.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 4.0 KiB |
BIN
eID_gui/images/info.png
Normal file
BIN
eID_gui/images/info.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 1.7 KiB |
BIN
eID_gui/images/wait.gif
Normal file
BIN
eID_gui/images/wait.gif
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 21 KiB |
15
eID_gui/src/Makefile.am
Normal file
15
eID_gui/src/Makefile.am
Normal file
@@ -0,0 +1,15 @@
|
|||||||
|
SUBDIRS = eid
|
||||||
|
bin_SCRIPTS = eid_gui.py
|
||||||
|
|
||||||
|
paceguidir = $(prefix)/bin
|
||||||
|
|
||||||
|
uidir = $(datadir)/eid_gui
|
||||||
|
ui_DATA = pinpad.glade
|
||||||
|
|
||||||
|
appdir = $(datadir)/applications/
|
||||||
|
app_DATA = pace-gui.desktop
|
||||||
|
|
||||||
|
EXTRA_DIST = \
|
||||||
|
$(bin_SCRIPTS) \
|
||||||
|
$(app_DATA) \
|
||||||
|
$(ui_DATA)
|
||||||
0
eID_gui/src/eid/__init__.py
Normal file
0
eID_gui/src/eid/__init__.py
Normal file
91
eID_gui/src/eid/eid_gui_globals.py.in
Normal file
91
eID_gui/src/eid/eid_gui_globals.py.in
Normal file
@@ -0,0 +1,91 @@
|
|||||||
|
#coding: utf-8
|
||||||
|
|
||||||
|
name = "pace-gui"
|
||||||
|
version = "@VERSION@"
|
||||||
|
image_dir = "@prefix@/share/" + name
|
||||||
|
glade_dir = "@prefix@/share/" + name
|
||||||
|
|
||||||
|
GLADE_FILE = glade_dir + "/pinpad.glade"
|
||||||
|
|
||||||
|
STR_NO_CARD = "<span fgcolor=\"red\" font=\"12\">Ausweis</span>"
|
||||||
|
STR_CARD_FOUND = "<span fgcolor=\"green\" font=\"12\">Ausweis</span>"
|
||||||
|
|
||||||
|
FILE_NO_CARD = image_dir + "/error.png"
|
||||||
|
FILE_CARD_FOUND = image_dir + "/apply.png"
|
||||||
|
|
||||||
|
EPA_ATR = "3b:84:80:01:00:00:90:00:95"
|
||||||
|
|
||||||
|
#The following strings are used as help texts for eID access rights
|
||||||
|
DOC_AGE_VERIFICATION = u"Die Altersverifikation erlaubt die Überprüfung, ob ein Nutzer alt genug ist um einen Dienst zu nutzen, ohne sein Geburtsdatum zu übertragen"
|
||||||
|
DOC_COMMUNITY_ID_VERIFICATION = u"Die Wohnort Verifikation erlaubt die Überprüfung, ob ein Nutzer in einem bestimmten Gebiet wohnt, ohne seine tatsächliche Adresse zu übertragen"
|
||||||
|
DOC_RESTRICTED_ID = u"Die Pseudonymfunktion macht einen Nutzer für den Dienstanbieter wiedererkennbar, ohne weitere Daten von ihm zu erfassen"
|
||||||
|
DOC_PRIVILEGED_TERMINAL = u"Ein privilegiertes Terminal darf auf den Kartenindividuellen Schlüssel des Ausweis zugreifen"
|
||||||
|
DOC_CAN_ALLOWED = u"Das Terminal darf die Funktionen des Ausweises mit der CAN nutzen"
|
||||||
|
DOC_PIN_MANAGMENT = u"Das Terminal darf die eID-Funktion (de-)aktivieren und eine neue eID-PIN setzen"
|
||||||
|
DOC_INSTALL_CERTIFICATE = u"Der Dienstanbieter darf ein Zertifikat im Ausweis installieren"
|
||||||
|
DOC_INSTALL_QC = u"Der Dienstanbieter darf ein qualifiziertes Zertifikat im Ausweis installieren"
|
||||||
|
DOC_DOCUMENT_TYPE = u"Der Dienstanbieter darf den Dokumenttyp (z.B. Personalausweis oder Aufenthaltstitel) auslesen"
|
||||||
|
DOC_STATE = u"Der Dienstanbieter darf die Staatzugehörigkeit des Ausweisinhabers lesen"
|
||||||
|
DOC_EXPIRY_DATE = u"Der Dienstanbieter darf das Ablaufdatum des Ausweises auslesen"
|
||||||
|
|
||||||
|
IMAGES = {
|
||||||
|
"apply": image_dir + "/apply.png",
|
||||||
|
"error": image_dir + "/error.png",
|
||||||
|
"info" : image_dir + "/info.png",
|
||||||
|
"wait" : image_dir + "/wait.gif"
|
||||||
|
}
|
||||||
|
|
||||||
|
#Authentication Terminal CHAT
|
||||||
|
AT_CHAT_STRINGS = {
|
||||||
|
#Age Verification
|
||||||
|
0: ("Altersverifikation", DOC_AGE_VERIFICATION),
|
||||||
|
#Community ID Verification
|
||||||
|
1: (u"Gemeindeschlüssel Verifikation", DOC_COMMUNITY_ID_VERIFICATION),
|
||||||
|
#Restrictied Identification
|
||||||
|
2: ("Pseudonymfunktion", DOC_RESTRICTED_ID),
|
||||||
|
#Privileged Terminal
|
||||||
|
3: ("Priviligiertes Terminal", DOC_PRIVILEGED_TERMINAL),
|
||||||
|
#CAN allowed
|
||||||
|
4: ("Verwendung der CAN", DOC_CAN_ALLOWED),
|
||||||
|
5: ("PIN Managment", DOC_PIN_MANAGMENT),
|
||||||
|
#Install Certificate
|
||||||
|
6: ("Zertifikat einspielen", DOC_INSTALL_CERTIFICATE),
|
||||||
|
#Install Qualified Certificate
|
||||||
|
7: ("Qualifiziertes Zertifikat einspielen", DOC_INSTALL_QC),
|
||||||
|
#Read DG 1
|
||||||
|
8: ("Dokumenttyp", DOC_DOCUMENT_TYPE),
|
||||||
|
#Read DG 2
|
||||||
|
9: ("Ausstellender Staat", DOC_STATE),
|
||||||
|
10: ("Ablaufdatum", DOC_EXPIRY_DATE), #Read DG 3
|
||||||
|
11: ("Vorname", None), #Read DG 4
|
||||||
|
12: ("Nachname", None), #Read DG 5
|
||||||
|
13: (u"Künstlername", None), #Read DG 6
|
||||||
|
14: ("Doktorgrad", None), #Read DG 7
|
||||||
|
15: ("Geburtsdatum", None), #Read DG 8
|
||||||
|
16: ("Geburtsort", None), #Read DG 9
|
||||||
|
17: (u"Ungültig", None), #Read DG 10
|
||||||
|
18: (u"Ungültig", None), #Read DG 11
|
||||||
|
19: (u"Ungültig", None),#Read DG 12
|
||||||
|
20: (u"Ungültig", None),#Read DG 13
|
||||||
|
21: (u"Ungültig", None),#Read DG 14
|
||||||
|
22: (u"Ungültig", None),#Read DG 15
|
||||||
|
23: (u"Ungültig", None),#Read DG 16
|
||||||
|
24: ("Adresse", None), #Read DG 17
|
||||||
|
25: (u"Gemeindeschlüssel lesen", None),#Read DG 18
|
||||||
|
26: (u"Ungültig", None),#Read DG 19
|
||||||
|
27: (u"Ungültig", None),#Read DG 20
|
||||||
|
28: (u"Ungültig", None),#Read DG 21
|
||||||
|
29: (u"Ungültig", None),#RFU
|
||||||
|
30: (u"Ungültig", None),#RFU
|
||||||
|
31: (u"Ungültig", None),#RFU
|
||||||
|
32: (u"Ungültig", None),#RFU
|
||||||
|
33: (u"Ungültig", None),#Write DG 21
|
||||||
|
34: (u"Ungültig", None),#Write DG 20
|
||||||
|
35: (u"Ungültig", None),#Write DG 19
|
||||||
|
36: (u"Gemeindeschlüssel schreiben", None),#Write DG 18
|
||||||
|
37: (u"Adresse schreiben", None)#Write DG 17"
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_CVC = "\x7F\x21\x82\x01\x41\x7F\x4E\x81\xFA\x5F\x29\x01\x00\x42\x0D\x5A\x5A\x44\x56\x43\x41\x41\x54\x41\x30\x30\x30\x33\x7F\x49\x4F\x06\x0A\x04\x00\x7F\x00\x07\x02\x02\x02\x02\x03\x86\x41\x04\x19\xD1\x75\x45\xD3\xFE\x0B\x34\x3E\x7E\xE2\xAE\x4E\x2B\xC9\x2D\x51\x35\x1C\xC1\x17\xA4\x7F\xA9\x51\x9A\xDB\x1E\x40\x5E\xE6\xB8\x12\x12\x80\xBC\xC2\xFF\xF0\x35\x7A\x19\x7D\xE7\x39\xA7\xFD\x2E\xF0\x22\x10\xEF\x34\x3C\xDB\xE7\x9E\xF9\x4B\x8E\x28\x59\x1B\xB9\x5F\x20\x0B\x5A\x5A\x44\x4B\x42\x32\x30\x30\x30\x30\x52\x7F\x4C\x12\x06\x09\x04\x00\x7F\x00\x07\x03\x01\x02\x02\x53\x05\x00\x03\x01\xDF\x04\x5F\x25\x06\x01\x00\x00\x02\x01\x07\x5F\x24\x06\x01\x00\x00\x03\x03\x01\x65\x5E\x73\x2D\x06\x09\x04\x00\x7F\x00\x07\x03\x01\x03\x01\x80\x20\x75\xE0\xC4\xAC\x36\xC2\x5A\x33\xAC\x0E\x9A\x75\xEB\x79\x2A\x72\xF3\x31\xA5\x1E\x28\x63\x4E\xCC\x2E\xD6\x2E\x54\xF3\xC6\x93\xDA\x73\x2D\x06\x09\x04\x00\x7F\x00\x07\x03\x01\x03\x02\x80\x20\x18\x12\x65\x74\x49\xFC\xF1\xD3\xDA\xD8\x3D\x13\x14\x29\x17\x5C\x61\x8B\x21\xBA\xF0\xAF\x44\xAC\xE3\x8C\xB2\xC1\x2C\xEB\x2A\x56\x5F\x37\x40\x54\x0F\x85\x09\x12\xAB\xD3\x51\xF8\xF5\x56\x9B\x53\x4A\x5C\x8F\x64\x54\x5B\x51\xA7\x34\x70\xBE\x5A\xD2\x89\xC1\x9A\x5E\x13\x52\x53\xD3\xBB\x15\x52\x26\x21\x7B\x41\xE7\xF0\x68\xB3\x52\x3F\x3A\x63\x92\x22\xAF\x2B\x62\x8C\x39\x7D\x4F\xD4\x02\x1E\xDE\x00\xDC"
|
||||||
|
|
||||||
|
TEST_DESCRIPTION = "\x30\x82\x01\x90\x06\x0A\x04\x00\x7F\x00\x07\x03\x01\x03\x01\x01\xA1\x16\x0C\x14\x42\x75\x6E\x64\x65\x73\x64\x72\x75\x63\x6B\x65\x72\x65\x69\x20\x47\x6D\x62\x48\xA2\x24\x13\x22\x68\x74\x74\x70\x3A\x2F\x2F\x77\x77\x77\x2E\x62\x75\x6E\x64\x65\x73\x64\x72\x75\x63\x6B\x65\x72\x65\x69\x2E\x64\x65\x2F\x64\x76\x63\x61\xA3\x18\x0C\x16\x44\x65\x75\x74\x73\x63\x68\x65\x20\x4B\x72\x65\x64\x69\x74\x62\x61\x6E\x6B\x20\x41\x47\xA4\x13\x13\x11\x68\x74\x74\x70\x3A\x2F\x2F\x77\x77\x77\x2E\x64\x6B\x62\x2E\x64\x65\xA5\x82\x01\x13\x0C\x82\x01\x0F\x54\x61\x75\x62\x65\x6E\x73\x74\x72\x2E\x20\x37\x2D\x39\x0D\x0A\x31\x30\x31\x31\x37\x20\x42\x65\x72\x6C\x69\x6E\x0D\x0A\x69\x6E\x66\x6F\x40\x64\x6B\x62\x2E\x64\x65\x0D\x0A\x45\x72\xC3\xB6\x66\x66\x6E\x75\x6E\x67\x20\x65\x69\x6E\x65\x73\x20\x4B\x6F\x6E\x74\x6F\x73\x0D\x0A\x42\x65\x72\x6C\x69\x6E\x65\x72\x20\x42\x65\x61\x75\x66\x74\x72\x61\x67\x74\x65\x72\x20\x66\xC3\xBC\x72\x20\x44\x61\x74\x65\x6E\x73\x63\x68\x75\x74\x7A\x20\x75\x6E\x64\x20\x49\x6E\x66\x6F\x72\x6D\x61\x74\x69\x6F\x6E\x73\x66\x72\x65\x69\x68\x65\x69\x74\x2C\x20\x41\x6E\x20\x64\x65\x72\x20\x55\x72\x61\x6E\x69\x61\x20\x34\x2D\x31\x30\x2C\x20\x31\x30\x37\x38\x37\x20\x42\x65\x72\x6C\x69\x6E\x2C\x20\x30\x33\x30\x2F\x31\x33\x20\x38\x38\x39\x2D\x30\x2C\x20\x6D\x61\x69\x6C\x62\x6F\x78\x40\x64\x61\x74\x65\x6E\x73\x63\x68\x75\x74\x7A\x2D\x62\x65\x72\x6C\x69\x6E\x2E\x64\x65\x2C\x20\x68\x74\x74\x70\x3A\x2F\x2F\x77\x77\x77\x2E\x64\x61\x74\x65\x6E\x73\x63\x68\x75\x74\x7A\x2D\x62\x65\x72\x6C\x69\x6E\x2E\x64\x65\x0D\x0A\x45\x72\xC3\xB6\x66\x66\x6E\x75\x6E\x67\x20\x65\x69\x6E\x65\x73\x20\x4B\x6F\x6E\x74\x6F\x73\x0D\x0A"
|
||||||
55
eID_gui/src/eid/logic.py
Normal file
55
eID_gui/src/eid/logic.py
Normal file
@@ -0,0 +1,55 @@
|
|||||||
|
import gobject
|
||||||
|
|
||||||
|
import subprocess
|
||||||
|
from threading import Thread, Event
|
||||||
|
from eid_gui_globals import STR_CARD_FOUND, STR_NO_CARD, IMAGES
|
||||||
|
|
||||||
|
class cardChecker(Thread):
|
||||||
|
""" This class searches for a card with a given ATR and displays
|
||||||
|
wether or not using a label and an image """
|
||||||
|
|
||||||
|
def __init__(self, lbl, img, atr, intervall=1):
|
||||||
|
Thread.__init__(self)
|
||||||
|
self._finished = Event()
|
||||||
|
self._paused = Event()
|
||||||
|
self.lbl = lbl
|
||||||
|
self.img = img
|
||||||
|
self.target_atr = atr
|
||||||
|
self.intervall = intervall
|
||||||
|
|
||||||
|
def _check_card(self):
|
||||||
|
"""
|
||||||
|
Actually this method should make use of pyscard, but I couldn't make
|
||||||
|
it run on the OpenMoko yet. Therefor we call opensc-tool instead, which
|
||||||
|
leads to higher delays """
|
||||||
|
|
||||||
|
proc = subprocess.Popen(["opensc-tool", "--atr"],
|
||||||
|
stdout=subprocess.PIPE, stderr=subprocess.PIPE, close_fds=True)
|
||||||
|
|
||||||
|
line = proc.stdout.readline().rstrip()
|
||||||
|
if line == self.target_atr:
|
||||||
|
gobject.idle_add(self.lbl.set_label, STR_CARD_FOUND)
|
||||||
|
gobject.idle_add(self.img.set_from_file, IMAGES["apply"])
|
||||||
|
else:
|
||||||
|
gobject.idle_add(self.lbl.set_label, STR_NO_CARD)
|
||||||
|
gobject.idle_add(self.img.set_from_file, IMAGES["error"])
|
||||||
|
|
||||||
|
def run(self):
|
||||||
|
"""Main loop: Poll the card if the thread is not paused or finished"""
|
||||||
|
while (True):
|
||||||
|
if self._finished.isSet():
|
||||||
|
return
|
||||||
|
if self._paused.isSet():
|
||||||
|
continue
|
||||||
|
self._check_card()
|
||||||
|
self._finished.wait(self.intervall)
|
||||||
|
|
||||||
|
def stop(self):
|
||||||
|
self._finished.set()
|
||||||
|
|
||||||
|
def pause(self):
|
||||||
|
self._paused.set()
|
||||||
|
|
||||||
|
def resume(self):
|
||||||
|
self._paused.clear()
|
||||||
|
|
||||||
65
eID_gui/src/eid/widgets.py
Normal file
65
eID_gui/src/eid/widgets.py
Normal file
@@ -0,0 +1,65 @@
|
|||||||
|
import sys
|
||||||
|
try:
|
||||||
|
import pygtk
|
||||||
|
pygtk.require("2.0")
|
||||||
|
import gtk, pango
|
||||||
|
except ImportError:
|
||||||
|
sys.exit(1)
|
||||||
|
|
||||||
|
from eid_gui_globals import AT_CHAT_STRINGS, IMAGES
|
||||||
|
|
||||||
|
class customCheckButton(object):
|
||||||
|
"""This class provides a custom version of gtk.CheckButton.
|
||||||
|
The main difference isthat the checkbox can be placed at the right
|
||||||
|
side of the label and that we can store an index with the button"""
|
||||||
|
|
||||||
|
def __init__(self, index, vbox):
|
||||||
|
self.idx = index
|
||||||
|
#Fetch name and (possibly empty) helptext
|
||||||
|
strings = AT_CHAT_STRINGS[index]
|
||||||
|
self.label = strings[0]
|
||||||
|
self.helptext = strings[1]
|
||||||
|
self.parent = vbox.get_parent_window()
|
||||||
|
|
||||||
|
#Setup a label with the name of the access right
|
||||||
|
self.lbl = gtk.Label(self.label)
|
||||||
|
self.lbl.set_alignment(0.0, 0.5)
|
||||||
|
self.lbl.set_padding(20, 0)
|
||||||
|
self.lbl.modify_font(pango.FontDescription("bold"))
|
||||||
|
|
||||||
|
#If we have a helptext, put an image at the left side of the label
|
||||||
|
self.info_box = None
|
||||||
|
if self.helptext is not None:
|
||||||
|
self.info_box = gtk.EventBox()
|
||||||
|
img = gtk.Image()
|
||||||
|
img.set_from_file(IMAGES["info"])
|
||||||
|
self.info_box.add(img)
|
||||||
|
self.info_box.connect("button_release_event", self._show_info)
|
||||||
|
|
||||||
|
#...and a checkbox on the right side of the label
|
||||||
|
self.chk = gtk.CheckButton("")
|
||||||
|
self.chk.set_active(True)
|
||||||
|
self.chk.set_alignment(1.0, 0.5)
|
||||||
|
|
||||||
|
#Insert the label and the checkbox in the vbox and add a seperator
|
||||||
|
hbox = gtk.HBox()
|
||||||
|
if self.info_box is not None:
|
||||||
|
hbox.pack_start(self.info_box, False, False)
|
||||||
|
else: #pack empty label for spacing
|
||||||
|
spacer = gtk.Label("")
|
||||||
|
spacer.set_size_request(32, 32)
|
||||||
|
hbox.pack_start(spacer, False, False)
|
||||||
|
hbox.pack_start(self.lbl, True, True)
|
||||||
|
hbox.pack_start(self.chk, False, False)
|
||||||
|
vbox.pack_start(gtk.HSeparator())
|
||||||
|
vbox.pack_start(hbox)
|
||||||
|
|
||||||
|
def is_active(self):
|
||||||
|
return self.chk.get_active()
|
||||||
|
|
||||||
|
def _show_info(self, widget=None, data=None):
|
||||||
|
"""Show a messagebox containing info about the access right in
|
||||||
|
question"""
|
||||||
|
help = MsgBox(self.parent, self.helptext, "info",
|
||||||
|
gtk.DIALOG_DESTROY_WITH_PARENT)
|
||||||
|
|
||||||
537
eID_gui/src/eid/windows.py
Normal file
537
eID_gui/src/eid/windows.py
Normal file
@@ -0,0 +1,537 @@
|
|||||||
|
#coding: utf-8
|
||||||
|
|
||||||
|
import sys, subprocess, os
|
||||||
|
try:
|
||||||
|
import pygtk
|
||||||
|
pygtk.require("2.0")
|
||||||
|
import gtk, gobject, glib, pango
|
||||||
|
except ImportError:
|
||||||
|
sys.exit(1)
|
||||||
|
|
||||||
|
try:
|
||||||
|
import pace
|
||||||
|
except ImportError:
|
||||||
|
print >> sys.stderr, "Could not import pace module, please install pyPACE"
|
||||||
|
sys.exit(1)
|
||||||
|
|
||||||
|
from eid_gui_globals import IMAGES, GLADE_FILE, EPA_ATR
|
||||||
|
from widgets import customCheckButton
|
||||||
|
from logic import cardChecker
|
||||||
|
|
||||||
|
class MokoWindow(gtk.Window):
|
||||||
|
"""
|
||||||
|
Base class for all our dialogues. It's a simple gtk.Window, with a title at
|
||||||
|
the top and to buttons at the bottom. In the middle there is a vBox where
|
||||||
|
we can put custom stuff for each dialoge.
|
||||||
|
All the dialoges are stored as a double-linked list, so the navigation from
|
||||||
|
one window to another is easy
|
||||||
|
"""
|
||||||
|
|
||||||
|
def __init__(self, title, predecessor):
|
||||||
|
super(MokoWindow, self).__init__()
|
||||||
|
|
||||||
|
self.title_str = title
|
||||||
|
self.predecessor = predecessor
|
||||||
|
|
||||||
|
assert(isinstance(self.title_str, basestring))
|
||||||
|
|
||||||
|
self.connect("destroy", gtk.main_quit)
|
||||||
|
#Display resolution of OpenMoko minus height of the SHR toolbar
|
||||||
|
self.set_size_request(480, 586)
|
||||||
|
#self.set_resizable(False)
|
||||||
|
|
||||||
|
#Main VBox, which consists of the title, the body, and the buttons
|
||||||
|
self.__vb = gtk.VBox(False, 5)
|
||||||
|
self.add(self.__vb)
|
||||||
|
|
||||||
|
#Title label at the top of the window
|
||||||
|
lbl_title = gtk.Label(self.title_str)
|
||||||
|
lbl_title.modify_font(pango.FontDescription("sans 14"))
|
||||||
|
lbl_title.set_alignment(0.5, 0.0)
|
||||||
|
self.__vb.pack_start(lbl_title, False, False)
|
||||||
|
|
||||||
|
#Body VBox for custom widgets
|
||||||
|
self.body = gtk.VBox(False)
|
||||||
|
#Add a scrollbar in case we must display lots of information
|
||||||
|
#Only use a vertical spacebar, not a horizontal one
|
||||||
|
scrolled_window = gtk.ScrolledWindow()
|
||||||
|
scrolled_window.set_policy(gtk.POLICY_NEVER, gtk.POLICY_AUTOMATIC)
|
||||||
|
scrolled_window.set_shadow_type(gtk.SHADOW_ETCHED_OUT)
|
||||||
|
self.__vb.pack_start(scrolled_window)
|
||||||
|
scrolled_window.add_with_viewport(self.body)
|
||||||
|
|
||||||
|
#Add two buttons at the bottom of the window
|
||||||
|
hbox = gtk.HBox(True, 5)
|
||||||
|
if self.predecessor is None:
|
||||||
|
btnBack = gtk.Button("Abbrechen")
|
||||||
|
else:
|
||||||
|
btnBack = gtk.Button(u"Zurück")
|
||||||
|
btnBack.set_size_request(150, 75)
|
||||||
|
btnBack.connect("clicked", self.btnBack_clicked, None)
|
||||||
|
if isinstance(btnBack.child, gtk.Label):
|
||||||
|
lbl = btnBack.child
|
||||||
|
else:
|
||||||
|
raise ValueError("Button does not have a label")
|
||||||
|
lbl.modify_font(pango.FontDescription("sans 12"))
|
||||||
|
hbox.pack_start(btnBack, True, True)
|
||||||
|
|
||||||
|
btnForward = gtk.Button("Weiter")
|
||||||
|
btnForward.set_size_request(150, 75)
|
||||||
|
btnForward.connect("clicked", self.btnForward_clicked, None)
|
||||||
|
if isinstance(btnForward.child, gtk.Label):
|
||||||
|
lbl = btnForward.child
|
||||||
|
else:
|
||||||
|
raise ValueError("Button does not have a label")
|
||||||
|
hbox.pack_start(btnForward, True, True)
|
||||||
|
lbl.modify_font(pango.FontDescription("sans 12"))
|
||||||
|
self.__vb.pack_start(hbox, False, False)
|
||||||
|
|
||||||
|
#Place window in the center of the screen
|
||||||
|
self.set_position(gtk.WIN_POS_CENTER_ALWAYS)
|
||||||
|
|
||||||
|
def btnBack_clicked(self, widget, data=None):
|
||||||
|
"""Go back to the previous window. If there is no previous window,
|
||||||
|
do nothing"""
|
||||||
|
if self.predecessor is None:
|
||||||
|
gtk.main_quit()
|
||||||
|
else:
|
||||||
|
self.predecessor.show_all()
|
||||||
|
self.hide()
|
||||||
|
|
||||||
|
def btnForward_clicked(self, widget, data=None):
|
||||||
|
"""Go to the next window. If there is no next window, do nothing"""
|
||||||
|
if self.successor is None:
|
||||||
|
pass
|
||||||
|
else:
|
||||||
|
self.successor.show_all()
|
||||||
|
self.hide()
|
||||||
|
|
||||||
|
|
||||||
|
class MsgBox(gtk.Dialog):
|
||||||
|
"""The gtk.MessageDialog looks like crap on the Moko, so we write our own"""
|
||||||
|
|
||||||
|
def __init__(self, parent, msg, img_type, flags):
|
||||||
|
#img is a string which is used as a key for the IMAGES dictionary
|
||||||
|
if img_type is not None:
|
||||||
|
assert IMAGES.has_key(img_type)
|
||||||
|
|
||||||
|
super(MsgBox, self).__init__(title="", parent=parent, flags=flags)
|
||||||
|
|
||||||
|
#Dialog will be resized to screen width no matter what. Therefore we
|
||||||
|
#use the whole width from the beginning to avoid being resized
|
||||||
|
self.set_size_request(480, 160)
|
||||||
|
|
||||||
|
hbox_top = gtk.HBox()
|
||||||
|
lbl = gtk.Label(msg)
|
||||||
|
lbl.set_width_chars(20)
|
||||||
|
lbl.set_line_wrap(True)
|
||||||
|
btn = gtk.Button("Ok")
|
||||||
|
btn.connect("clicked", self.__destroy)
|
||||||
|
img = gtk.Image()
|
||||||
|
img.set_from_file(IMAGES[img_type])
|
||||||
|
hbox_top.pack_start(img, False, False)
|
||||||
|
hbox_top.pack_start(lbl, True, True)
|
||||||
|
self.vbox.pack_start(hbox_top)
|
||||||
|
#self.vbox.pack_start(gtk.HSeparator())
|
||||||
|
hbox_bottom = gtk.HBox()
|
||||||
|
spacer = gtk.Label("")
|
||||||
|
spacer.set_size_request(380, 25)
|
||||||
|
hbox_bottom.pack_start(spacer, False, False)
|
||||||
|
hbox_bottom.pack_start(btn, True, True)
|
||||||
|
self.vbox.pack_start(hbox_bottom)
|
||||||
|
#hbox.pack_start(vbox)
|
||||||
|
#self.add(hbox)
|
||||||
|
|
||||||
|
#self.set_decorated(False)
|
||||||
|
self.set_modal(True)
|
||||||
|
|
||||||
|
self.show_all()
|
||||||
|
|
||||||
|
def __destroy(self, widget=None, data=None):
|
||||||
|
self.destroy()
|
||||||
|
|
||||||
|
|
||||||
|
class CertificateDescriptionWindow(MokoWindow):
|
||||||
|
"""This window is used to display information about the service provider,
|
||||||
|
extracted from the terminal certificate and the appendant certificate
|
||||||
|
description"""
|
||||||
|
|
||||||
|
def __init__(self, binDescription, binCert):
|
||||||
|
super(CertificateDescriptionWindow, self).__init__("Dienstanbieter", None)
|
||||||
|
|
||||||
|
#binDesciption contains the Certificate Description as a octet string
|
||||||
|
desc = pace.d2i_CVC_CERTIFICATE_DESCRIPTION(binDescription)
|
||||||
|
|
||||||
|
self.successor = CVCWindow(binCert, self)
|
||||||
|
|
||||||
|
#Display the validity period:
|
||||||
|
cvc = pace.d2i_CV_CERT(binCert)
|
||||||
|
effective_date = self.formatDate(pace.get_effective_date(cvc))
|
||||||
|
expiration_date = self.formatDate(pace.get_expiration_date(cvc))
|
||||||
|
validity_period = effective_date + " - " + expiration_date
|
||||||
|
#self.addRow(u"Gültig ab:", effective_date)
|
||||||
|
#self.addRow(u"Gültig bis:", expiration_date)
|
||||||
|
self.addRow(u"Gültigkeitszeitraum:", validity_period)
|
||||||
|
|
||||||
|
#Display issuer Name and possibly URL and subject name and possibly URL
|
||||||
|
issuer_name = pace.get_issuer_name(desc)
|
||||||
|
issuer_url = pace.get_issuer_url(desc)
|
||||||
|
self.addRow("Zertifikatsaussteller:", issuer_name)
|
||||||
|
if issuer_url is not None:
|
||||||
|
self.addRow("", issuer_url, True)
|
||||||
|
subject_name = pace.get_subject_name(desc)
|
||||||
|
subject_url = pace.get_subject_url(desc)
|
||||||
|
self.addRow("Zertifikatsinhaber:", subject_name)
|
||||||
|
if subject_url is not None:
|
||||||
|
self.addRow("", subject_url, True)
|
||||||
|
self.set_focus(None)
|
||||||
|
|
||||||
|
#Extract, format and display the terms of usage
|
||||||
|
terms = pace.get_termsOfUsage(desc)
|
||||||
|
formated_terms = self.formatTOU(terms)
|
||||||
|
self.addRow("Beschreibung:", formated_terms)
|
||||||
|
|
||||||
|
self.show_all()
|
||||||
|
|
||||||
|
def formatDate(self, date):
|
||||||
|
"""Take a date string in the form that is included in CV Certificates
|
||||||
|
(YYMMDD) and return it in a better readable format (DD.MM.YYYY)"""
|
||||||
|
|
||||||
|
assert(isinstance(date, basestring))
|
||||||
|
assert(len(date) == 6)
|
||||||
|
|
||||||
|
year = date[:2]
|
||||||
|
month = date[2:4]
|
||||||
|
day = date[4:6] #Cut off trailing \0
|
||||||
|
|
||||||
|
#Implicit assumption: 2000 <= year < 3000
|
||||||
|
return day + "." + month + "." + "20" + year
|
||||||
|
|
||||||
|
def formatTOU(self, terms):
|
||||||
|
|
||||||
|
# for s in self.terms_array:
|
||||||
|
# s = s.replace(", ", "\n").strip()
|
||||||
|
# lbl = gtk.Label(s)
|
||||||
|
# lbl.set_alignment(0.0, 0.0)
|
||||||
|
# lbl.set_width_chars(60)
|
||||||
|
# lbl.set_line_wrap(True) #XXX: Doesn't work on the Moko
|
||||||
|
# lbl.modify_font(pango.FontDescription("bold"))
|
||||||
|
# self.body.pack_start(gtk.HSeparator())
|
||||||
|
# self.body.pack_start(lbl, False, False, 2)
|
||||||
|
|
||||||
|
return terms.replace(", ", "\r\n")
|
||||||
|
|
||||||
|
def addRow(self, title, text, url=False):
|
||||||
|
if not url: #URL has no title
|
||||||
|
lbl_title = gtk.Label(title)
|
||||||
|
lbl_title.set_width_chars(20)
|
||||||
|
lbl_title.set_alignment(0.0, 0.5)
|
||||||
|
lbl_title.modify_font(pango.FontDescription("bold"))
|
||||||
|
self.body.pack_start(lbl_title)
|
||||||
|
hbox = gtk.HBox()
|
||||||
|
lbl = gtk.Label("") #Empty label for spacing
|
||||||
|
lbl.set_width_chars(3)
|
||||||
|
hbox.pack_start(lbl)
|
||||||
|
if url:
|
||||||
|
lblText = gtk.LinkButton(text, text)
|
||||||
|
if isinstance(lblText.child, gtk.Label):
|
||||||
|
lbl = lblText.child
|
||||||
|
else:
|
||||||
|
raise ValueError("Button does not have a label")
|
||||||
|
lbl.set_width_chars(40)
|
||||||
|
|
||||||
|
else:
|
||||||
|
lblText = gtk.Label(text)
|
||||||
|
lblText.set_width_chars(40)
|
||||||
|
|
||||||
|
lblText.set_alignment(0.0, 0.0)
|
||||||
|
hbox.pack_start(lblText)
|
||||||
|
self.body.pack_start(hbox)
|
||||||
|
|
||||||
|
class CVCWindow(MokoWindow):
|
||||||
|
"""This window is used to display and modify the access encoded in the CHAT
|
||||||
|
of a CV Certificate"""
|
||||||
|
|
||||||
|
def __init__(self, binCert, predecessor):
|
||||||
|
super(CVCWindow, self).__init__("Zugriffsrechte", predecessor)
|
||||||
|
|
||||||
|
self.successor = PinpadGTK("pin", None)
|
||||||
|
|
||||||
|
#Convert the binary certificate to the internal representation and
|
||||||
|
#extract the relative authorization from the chat
|
||||||
|
cvc = pace.d2i_CV_CERT(binCert)
|
||||||
|
chat = pace.cvc_get_chat(cvc)
|
||||||
|
self.chat_oid = pace.get_chat_oid(chat)
|
||||||
|
self.chat = pace.get_binary_chat(chat)
|
||||||
|
self.rel_auth = []
|
||||||
|
for char in self.chat:
|
||||||
|
self.rel_auth.append(ord(char))
|
||||||
|
self.rel_auth_len = len(self.rel_auth)
|
||||||
|
|
||||||
|
#Extract the access rights from the CHAT and display them in the window
|
||||||
|
self.access_rights = []
|
||||||
|
j = 0
|
||||||
|
for i in range((self.rel_auth_len - 1) * 8 - 2):
|
||||||
|
if (i % 8 == 0):
|
||||||
|
j += 1
|
||||||
|
if self.rel_auth[self.rel_auth_len - j] & (1 << (i % 8)):
|
||||||
|
chk = customCheckButton(i, self.body)
|
||||||
|
self.access_rights.append(chk)
|
||||||
|
|
||||||
|
def btnForward_clicked(self, widget, data=None):
|
||||||
|
""" Check wether any access right have been deselected and modify the
|
||||||
|
CHAT accordingly """
|
||||||
|
|
||||||
|
for right in self.access_rights:
|
||||||
|
if not right.is_active():
|
||||||
|
idx = right.idx
|
||||||
|
self.rel_auth[len(self.chat) - 1 - idx / 8] ^= (1 << (idx % 8))
|
||||||
|
|
||||||
|
#super(CVCWindow, self).btnForward_clicked(widget, data)
|
||||||
|
new_chat_list = []
|
||||||
|
for byte in self.chat_oid:
|
||||||
|
new_chat_list.append(ord(byte))
|
||||||
|
new_chat_list.append(len(self.rel_auth))
|
||||||
|
new_chat_list.extend(self.rel_auth)
|
||||||
|
new_chat = self.__formatHexString(new_chat_list)
|
||||||
|
self.successor.set_chat(new_chat)
|
||||||
|
self.successor.show()
|
||||||
|
self.hide()
|
||||||
|
|
||||||
|
def __formatHexString(self, int_list):
|
||||||
|
"""Take a list of integers and convert it to a hex string, where the
|
||||||
|
individual bytes are seperated by a colon (e.g. "0f:00:00")"""
|
||||||
|
hex_str = ""
|
||||||
|
for i in int_list:
|
||||||
|
byte = hex(i)[2:]
|
||||||
|
if len(byte) == 1: byte = "0" + byte
|
||||||
|
hex_str += byte + ":"
|
||||||
|
|
||||||
|
return hex_str[:-1]
|
||||||
|
|
||||||
|
class PinpadGTK:
|
||||||
|
"""This a simple GTK based GUI to enter a PIN/PUK/CAN"""
|
||||||
|
|
||||||
|
def __init__(self, secret="pin", chat=None, cert=None):
|
||||||
|
btn_names = ["btnOne", "btnTwo", "btnThree", "btnFour", "btnFive",
|
||||||
|
"btnSix", "btnSeven", "btnEight", "btnNine", "btnDel",
|
||||||
|
"btnZero", "btnOk"]
|
||||||
|
|
||||||
|
self.pin = ""
|
||||||
|
self.secret = secret
|
||||||
|
if self.secret == "pin" or self.secret == "can":
|
||||||
|
self.secret_len = 6
|
||||||
|
elif self.secret == "transport":
|
||||||
|
self.secret_len = 5
|
||||||
|
elif self.secret == "puk":
|
||||||
|
self.secret_len = 10
|
||||||
|
else:
|
||||||
|
raise ValueError("Unknwon secret type: %s" % self.secret)
|
||||||
|
#gtk.main_quit()
|
||||||
|
self.chat = chat
|
||||||
|
self.cert = cert
|
||||||
|
|
||||||
|
#Set the Glade file
|
||||||
|
self.gladefile = GLADE_FILE
|
||||||
|
self.builder = gtk.Builder()
|
||||||
|
try:
|
||||||
|
self.builder.add_from_file(self.gladefile)
|
||||||
|
except glib.GError, err:
|
||||||
|
#If we encounter an exception at startup, we display a popup with
|
||||||
|
#the error message
|
||||||
|
popup = MsgBox(None, err.message, "error", None)
|
||||||
|
popup.run()
|
||||||
|
popup.destroy()
|
||||||
|
raise err
|
||||||
|
|
||||||
|
#Get the Main Window, and connect the "destroy" event
|
||||||
|
#Create our dictionay and connect it
|
||||||
|
dic = { "on_btnOne_clicked" : self.digit_clicked,
|
||||||
|
"on_btnTwo_clicked" : self.digit_clicked,
|
||||||
|
"on_btnThree_clicked" : self.digit_clicked,
|
||||||
|
"on_btnFour_clicked" : self.digit_clicked,
|
||||||
|
"on_btnFive_clicked" : self.digit_clicked,
|
||||||
|
"on_btnSix_clicked" : self.digit_clicked,
|
||||||
|
"on_btnSeven_clicked" : self.digit_clicked,
|
||||||
|
"on_btnEight_clicked" : self.digit_clicked,
|
||||||
|
"on_btnNine_clicked" : self.digit_clicked,
|
||||||
|
"on_btnZero_clicked" : self.digit_clicked,
|
||||||
|
"on_btnOk_clicked" : self.btnOk_clicked,
|
||||||
|
"on_btnDel_clicked" : self.btnDel_clicked,
|
||||||
|
"on_MainWindow_destroy_event" : self.shutdown,
|
||||||
|
"on_MainWindow_destroy" : self.shutdown }
|
||||||
|
|
||||||
|
self.builder.connect_signals(dic)
|
||||||
|
|
||||||
|
#Change the font for the text field and set it up up properly for the
|
||||||
|
#type of secret we are using
|
||||||
|
self.output = self.builder.get_object("txtOutput")
|
||||||
|
self.output.modify_font(pango.FontDescription("Monospace 16"))
|
||||||
|
self.output.set_text(self.secret_len * "_")
|
||||||
|
|
||||||
|
#Look for card and set the label accordingly
|
||||||
|
self.lbl_cardStatus = self.builder.get_object("lbl_cardStatus")
|
||||||
|
#Fetch the status image
|
||||||
|
self.img_cardStatus = self.builder.get_object("img_cardStatus")
|
||||||
|
self.img_cardStatus.set_from_file(IMAGES["error"])
|
||||||
|
|
||||||
|
#We only start the thread for polling the card when the window
|
||||||
|
#is shown
|
||||||
|
self.cardChecker = None
|
||||||
|
|
||||||
|
#Change the font for the buttons
|
||||||
|
#For this you have to retrieve the label of each button and change
|
||||||
|
#its font
|
||||||
|
for btn_name in btn_names:
|
||||||
|
btn = self.builder.get_object(btn_name)
|
||||||
|
if btn.get_use_stock():
|
||||||
|
lbl = btn.child.get_children()[1]
|
||||||
|
elif isinstance(btn.child, gtk.Label):
|
||||||
|
lbl = btn.child
|
||||||
|
else:
|
||||||
|
raise ValueError("Button does not have a label")
|
||||||
|
|
||||||
|
if (btn_name == "btnOk" or btn_name == "btnDel"):
|
||||||
|
lbl.modify_font(pango.FontDescription("sans 14"))
|
||||||
|
else:
|
||||||
|
lbl.modify_font(pango.FontDescription("sans 18"))
|
||||||
|
|
||||||
|
#Display Main Window
|
||||||
|
self.window = self.builder.get_object("MainWindow")
|
||||||
|
self.window.connect("destroy", self.shutdown)
|
||||||
|
self.window.hide()
|
||||||
|
|
||||||
|
def show(self):
|
||||||
|
"""Start the polling thread, then show the window"""
|
||||||
|
if self.cardChecker is None:
|
||||||
|
self.cardChecker = cardChecker(self.lbl_cardStatus, self.img_cardStatus,
|
||||||
|
EPA_ATR)
|
||||||
|
gobject.idle_add(self.cardChecker.start)
|
||||||
|
self.window.show_all()
|
||||||
|
|
||||||
|
def set_chat(self, chat):
|
||||||
|
self.chat = chat
|
||||||
|
|
||||||
|
def shutdown(self, widget):
|
||||||
|
"""Stop the cardChecker thread before exiting the application"""
|
||||||
|
if self.cardChecker is not None:
|
||||||
|
self.cardChecker.stop()
|
||||||
|
self.cardChecker.join()
|
||||||
|
gtk.main_quit()
|
||||||
|
|
||||||
|
def digit_clicked(self, widget):
|
||||||
|
"""We indicate the ammount of digits with underscores
|
||||||
|
For every digit that is enterd we replace one underscore with a star
|
||||||
|
We only accept secret_len digits and ignore every additional digit"""
|
||||||
|
digit = widget.get_label()
|
||||||
|
assert digit.isdigit()
|
||||||
|
txt = self.output.get_text()
|
||||||
|
if len(self.pin) < self.secret_len:
|
||||||
|
# self.output.set_text(txt.replace("_", digit, 1))
|
||||||
|
idx = txt.find('_')
|
||||||
|
output = txt[:idx] + digit + txt[idx+1:]
|
||||||
|
self.output.set_text(output)
|
||||||
|
gobject.timeout_add(750, self.hide_digits, idx)
|
||||||
|
self.pin += digit
|
||||||
|
|
||||||
|
def hide_digits(self, idx):
|
||||||
|
"""Change character number idx of self.output text to a '*' """
|
||||||
|
output = ""
|
||||||
|
txt = self.output.get_text()
|
||||||
|
if txt[idx].isdigit():
|
||||||
|
output = txt[:idx] + '*' + txt[idx+1:]
|
||||||
|
self.output.set_text(output)
|
||||||
|
return False
|
||||||
|
|
||||||
|
def btnOk_clicked(self, widget):
|
||||||
|
"""Pass the entered secret to pace-tool. If pace-tool is run
|
||||||
|
sucessfully exit, otherwise restart the PIN entry"""
|
||||||
|
|
||||||
|
env_args = os.environ
|
||||||
|
|
||||||
|
#cmd contains the command and all the parameters for our subproccess
|
||||||
|
cmd = ["pace-tool"]
|
||||||
|
|
||||||
|
#We have to select the type of secret to use via a command line
|
||||||
|
#parameter and provide the actual secret via an environment variable
|
||||||
|
if self.secret == "pin" or self.secret == "transport":
|
||||||
|
cmd.append("--pin")
|
||||||
|
env_args["PIN"] = self.pin
|
||||||
|
elif self.secret == "can":
|
||||||
|
cmd.append("--can")
|
||||||
|
env_args["CAN"] = self.pin
|
||||||
|
elif self.secret == "puk":
|
||||||
|
cmd.append("--puk")
|
||||||
|
env_args["PUK"] = self.pin
|
||||||
|
else:
|
||||||
|
raise ValueError("Unknown secret type: %s" % self.secret)
|
||||||
|
|
||||||
|
#If we have a CHAT, we pass it to pace-tool
|
||||||
|
if (self.chat):
|
||||||
|
cmd.append("--chat=" + self.chat)
|
||||||
|
|
||||||
|
cmd.append("-v")
|
||||||
|
|
||||||
|
#Try to call pace-tool. This is a blocking call. An animation is being
|
||||||
|
#shown while the subprocess is running
|
||||||
|
try:
|
||||||
|
#Stop polling the card while PACE is running
|
||||||
|
self.cardChecker.pause()
|
||||||
|
proc = subprocess.Popen(cmd, stdout=subprocess.PIPE, env=env_args,
|
||||||
|
close_fds=True)
|
||||||
|
except OSError:
|
||||||
|
popup = MsgBox(self.window, "pace-tool wurde nicht gefunden",
|
||||||
|
"error", gtk.DIALOG_DESTROY_WITH_PARENT)
|
||||||
|
popup.run()
|
||||||
|
popup.destroy()
|
||||||
|
self.cardChecker.resume() #Restart cardChecker
|
||||||
|
return
|
||||||
|
|
||||||
|
#Show the animation to indicate that the program is not dead
|
||||||
|
waiting = gtk.Window(gtk.WINDOW_POPUP)
|
||||||
|
animation = gtk.gdk.PixbufAnimation(IMAGES["wait"])
|
||||||
|
img = gtk.Image()
|
||||||
|
img.set_from_animation(animation)
|
||||||
|
waiting.add(img)
|
||||||
|
waiting.set_position(gtk.WIN_POS_CENTER_ALWAYS)
|
||||||
|
waiting.set_modal(True)
|
||||||
|
waiting.set_transient_for(self.window)
|
||||||
|
waiting.set_decorated(False)
|
||||||
|
waiting.show_all()
|
||||||
|
|
||||||
|
#Try to keep the GUI responsive by taking care of the event queue
|
||||||
|
line = proc.stdout.readline()
|
||||||
|
while line:
|
||||||
|
while gtk.events_pending():
|
||||||
|
gtk.main_iteration()
|
||||||
|
line = proc.stdout.readline()
|
||||||
|
|
||||||
|
#Get the return value of the pace-tool process
|
||||||
|
ret = proc.poll()
|
||||||
|
waiting.destroy()
|
||||||
|
self.cardChecker.resume()
|
||||||
|
|
||||||
|
if (ret == 0):
|
||||||
|
popup = MsgBox(self.window, "Pin wurde korrekt eingegeben", "apply",
|
||||||
|
gtk.DIALOG_DESTROY_WITH_PARENT)
|
||||||
|
popup.run()
|
||||||
|
popup.destroy()
|
||||||
|
#XXX: Actually we should return to the application that started
|
||||||
|
#the PIN entry
|
||||||
|
self.shutdown(None)
|
||||||
|
else:
|
||||||
|
popup = MsgBox(self.window, "PIN wurde falsch eingegeben", "error",
|
||||||
|
gtk.DIALOG_MODAL | gtk.DIALOG_DESTROY_WITH_PARENT)
|
||||||
|
popup.run()
|
||||||
|
popup.destroy()
|
||||||
|
self.output.set_text(self.secret_len * "_")
|
||||||
|
self.pin = ""
|
||||||
|
|
||||||
|
def btnDel_clicked(self, widget):
|
||||||
|
"""Remove one digit from the pin and replace the last * in the output
|
||||||
|
field with an underscore"""
|
||||||
|
self.pin = self.pin[:-1]
|
||||||
|
num_digits = len(self.pin)
|
||||||
|
output = num_digits * '*' + (self.secret_len - num_digits) * "_"
|
||||||
|
self.output.set_text(output)
|
||||||
|
|
||||||
18
eID_gui/src/eid_gui.py
Normal file
18
eID_gui/src/eid_gui.py
Normal file
@@ -0,0 +1,18 @@
|
|||||||
|
#!/usr/bin/env python
|
||||||
|
# coding: utf-8
|
||||||
|
|
||||||
|
import sys, os, subprocess
|
||||||
|
try:
|
||||||
|
import pygtk
|
||||||
|
pygtk.require("2.0")
|
||||||
|
import gtk, gobject
|
||||||
|
except ImportError:
|
||||||
|
sys.exit(1)
|
||||||
|
|
||||||
|
from eid.eid_gui_globals import TEST_DESCRIPTION, TEST_CVC
|
||||||
|
from eid.windows import CertificateDescriptionWindow
|
||||||
|
|
||||||
|
if __name__ == "__main__":
|
||||||
|
gobject.threads_init()
|
||||||
|
CertificateDescriptionWindow(TEST_DESCRIPTION, TEST_CVC)
|
||||||
|
gtk.main()
|
||||||
11
eID_gui/src/pace-gui.desktop.in
Normal file
11
eID_gui/src/pace-gui.desktop.in
Normal file
@@ -0,0 +1,11 @@
|
|||||||
|
[Desktop Entry]
|
||||||
|
Version=@VERSION@
|
||||||
|
Encoding=UTF-8
|
||||||
|
Name=PACE-GUI
|
||||||
|
Comment=GUI zur Eingabe einer PIN/CAN/PUK fuer pace-tool
|
||||||
|
Exec=eid_gui.py
|
||||||
|
Icon=@prefix@/share/pace-gui/OpenPACElogo.png
|
||||||
|
Terminal=false
|
||||||
|
Type=Application
|
||||||
|
Categories=Utility
|
||||||
|
StartupNotify=false
|
||||||
272
eID_gui/src/pinpad.glade
Normal file
272
eID_gui/src/pinpad.glade
Normal file
@@ -0,0 +1,272 @@
|
|||||||
|
<?xml version="1.0"?>
|
||||||
|
<interface>
|
||||||
|
<requires lib="gtk+" version="2.16"/>
|
||||||
|
<!-- interface-naming-policy project-wide -->
|
||||||
|
<object class="GtkWindow" id="MainWindow">
|
||||||
|
<property name="visible">True</property>
|
||||||
|
<property name="title" translatable="yes">Pinpad</property>
|
||||||
|
<property name="window_position">center</property>
|
||||||
|
<property name="default_width">480</property>
|
||||||
|
<property name="default_height">586</property>
|
||||||
|
<property name="icon">OpenPACElogo.png</property>
|
||||||
|
<signal name="destroy" handler="on_MainWindow_destroy"/>
|
||||||
|
<signal name="destroy_event" handler="on_MainWindow_destroy_event"/>
|
||||||
|
<child>
|
||||||
|
<object class="GtkVBox" id="vbox1">
|
||||||
|
<property name="visible">True</property>
|
||||||
|
<child>
|
||||||
|
<object class="GtkLabel" id="lblInstruction">
|
||||||
|
<property name="visible">True</property>
|
||||||
|
<property name="label" translatable="yes"><span font_weight="bold" font="11">Bitte PIN eingeben</span></property>
|
||||||
|
<property name="use_markup">True</property>
|
||||||
|
</object>
|
||||||
|
<packing>
|
||||||
|
<property name="expand">False</property>
|
||||||
|
<property name="position">0</property>
|
||||||
|
</packing>
|
||||||
|
</child>
|
||||||
|
<child>
|
||||||
|
<object class="GtkHSeparator" id="hseparator2">
|
||||||
|
<property name="visible">True</property>
|
||||||
|
</object>
|
||||||
|
<packing>
|
||||||
|
<property name="expand">False</property>
|
||||||
|
<property name="position">1</property>
|
||||||
|
</packing>
|
||||||
|
</child>
|
||||||
|
<child>
|
||||||
|
<object class="GtkEntry" id="txtOutput">
|
||||||
|
<property name="visible">True</property>
|
||||||
|
<property name="sensitive">False</property>
|
||||||
|
<property name="editable">False</property>
|
||||||
|
<property name="max_length">10</property>
|
||||||
|
<property name="invisible_char">●</property>
|
||||||
|
<property name="width_chars">0</property>
|
||||||
|
<property name="truncate_multiline">True</property>
|
||||||
|
<property name="shadow_type">out</property>
|
||||||
|
<property name="invisible_char_set">True</property>
|
||||||
|
<property name="caps_lock_warning">False</property>
|
||||||
|
</object>
|
||||||
|
<packing>
|
||||||
|
<property name="expand">False</property>
|
||||||
|
<property name="padding">5</property>
|
||||||
|
<property name="position">2</property>
|
||||||
|
</packing>
|
||||||
|
</child>
|
||||||
|
<child>
|
||||||
|
<object class="GtkHSeparator" id="hseparator1">
|
||||||
|
<property name="visible">True</property>
|
||||||
|
</object>
|
||||||
|
<packing>
|
||||||
|
<property name="expand">False</property>
|
||||||
|
<property name="position">3</property>
|
||||||
|
</packing>
|
||||||
|
</child>
|
||||||
|
<child>
|
||||||
|
<object class="GtkHBox" id="hbox1">
|
||||||
|
<property name="visible">True</property>
|
||||||
|
<child>
|
||||||
|
<object class="GtkLabel" id="lbl_cardStatus">
|
||||||
|
<property name="visible">True</property>
|
||||||
|
<property name="xalign">0.89999997615814209</property>
|
||||||
|
<property name="label" translatable="yes"><span fgcolor="red" font="12">Ausweis</span></property>
|
||||||
|
<property name="use_markup">True</property>
|
||||||
|
</object>
|
||||||
|
<packing>
|
||||||
|
<property name="position">0</property>
|
||||||
|
</packing>
|
||||||
|
</child>
|
||||||
|
<child>
|
||||||
|
<object class="GtkImage" id="img_cardStatus">
|
||||||
|
<property name="visible">True</property>
|
||||||
|
<property name="xalign">0.10000000149011612</property>
|
||||||
|
<property name="pixbuf">error.png</property>
|
||||||
|
</object>
|
||||||
|
<packing>
|
||||||
|
<property name="position">1</property>
|
||||||
|
</packing>
|
||||||
|
</child>
|
||||||
|
</object>
|
||||||
|
<packing>
|
||||||
|
<property name="position">4</property>
|
||||||
|
</packing>
|
||||||
|
</child>
|
||||||
|
<child>
|
||||||
|
<object class="GtkTable" id="table1">
|
||||||
|
<property name="visible">True</property>
|
||||||
|
<property name="n_rows">4</property>
|
||||||
|
<property name="n_columns">3</property>
|
||||||
|
<property name="homogeneous">True</property>
|
||||||
|
<child>
|
||||||
|
<object class="GtkButton" id="btnOne">
|
||||||
|
<property name="label" translatable="yes">1</property>
|
||||||
|
<property name="visible">True</property>
|
||||||
|
<property name="can_focus">True</property>
|
||||||
|
<property name="receives_default">True</property>
|
||||||
|
<signal name="clicked" handler="on_btnOne_clicked"/>
|
||||||
|
</object>
|
||||||
|
</child>
|
||||||
|
<child>
|
||||||
|
<object class="GtkButton" id="btnFour">
|
||||||
|
<property name="label" translatable="yes">4</property>
|
||||||
|
<property name="visible">True</property>
|
||||||
|
<property name="can_focus">True</property>
|
||||||
|
<property name="receives_default">True</property>
|
||||||
|
<signal name="clicked" handler="on_btnFour_clicked"/>
|
||||||
|
</object>
|
||||||
|
<packing>
|
||||||
|
<property name="top_attach">1</property>
|
||||||
|
<property name="bottom_attach">2</property>
|
||||||
|
</packing>
|
||||||
|
</child>
|
||||||
|
<child>
|
||||||
|
<object class="GtkButton" id="btnSeven">
|
||||||
|
<property name="label" translatable="yes">7</property>
|
||||||
|
<property name="visible">True</property>
|
||||||
|
<property name="can_focus">True</property>
|
||||||
|
<property name="receives_default">True</property>
|
||||||
|
<signal name="clicked" handler="on_btnSeven_clicked"/>
|
||||||
|
</object>
|
||||||
|
<packing>
|
||||||
|
<property name="top_attach">2</property>
|
||||||
|
<property name="bottom_attach">3</property>
|
||||||
|
</packing>
|
||||||
|
</child>
|
||||||
|
<child>
|
||||||
|
<object class="GtkButton" id="btnDel">
|
||||||
|
<property name="label">Entf</property>
|
||||||
|
<property name="visible">True</property>
|
||||||
|
<property name="can_focus">True</property>
|
||||||
|
<property name="receives_default">True</property>
|
||||||
|
<signal name="clicked" handler="on_btnDel_clicked"/>
|
||||||
|
</object>
|
||||||
|
<packing>
|
||||||
|
<property name="top_attach">3</property>
|
||||||
|
<property name="bottom_attach">4</property>
|
||||||
|
</packing>
|
||||||
|
</child>
|
||||||
|
<child>
|
||||||
|
<object class="GtkButton" id="btnTwo">
|
||||||
|
<property name="label" translatable="yes">2</property>
|
||||||
|
<property name="visible">True</property>
|
||||||
|
<property name="can_focus">True</property>
|
||||||
|
<property name="receives_default">True</property>
|
||||||
|
<signal name="clicked" handler="on_btnTwo_clicked"/>
|
||||||
|
</object>
|
||||||
|
<packing>
|
||||||
|
<property name="left_attach">1</property>
|
||||||
|
<property name="right_attach">2</property>
|
||||||
|
</packing>
|
||||||
|
</child>
|
||||||
|
<child>
|
||||||
|
<object class="GtkButton" id="btnFive">
|
||||||
|
<property name="label" translatable="yes">5</property>
|
||||||
|
<property name="visible">True</property>
|
||||||
|
<property name="can_focus">True</property>
|
||||||
|
<property name="receives_default">True</property>
|
||||||
|
<signal name="clicked" handler="on_btnFive_clicked"/>
|
||||||
|
</object>
|
||||||
|
<packing>
|
||||||
|
<property name="left_attach">1</property>
|
||||||
|
<property name="right_attach">2</property>
|
||||||
|
<property name="top_attach">1</property>
|
||||||
|
<property name="bottom_attach">2</property>
|
||||||
|
</packing>
|
||||||
|
</child>
|
||||||
|
<child>
|
||||||
|
<object class="GtkButton" id="btnEight">
|
||||||
|
<property name="label" translatable="yes">8</property>
|
||||||
|
<property name="visible">True</property>
|
||||||
|
<property name="can_focus">True</property>
|
||||||
|
<property name="receives_default">True</property>
|
||||||
|
<signal name="clicked" handler="on_btnEight_clicked"/>
|
||||||
|
</object>
|
||||||
|
<packing>
|
||||||
|
<property name="left_attach">1</property>
|
||||||
|
<property name="right_attach">2</property>
|
||||||
|
<property name="top_attach">2</property>
|
||||||
|
<property name="bottom_attach">3</property>
|
||||||
|
</packing>
|
||||||
|
</child>
|
||||||
|
<child>
|
||||||
|
<object class="GtkButton" id="btnZero">
|
||||||
|
<property name="label" translatable="yes">0</property>
|
||||||
|
<property name="visible">True</property>
|
||||||
|
<property name="can_focus">True</property>
|
||||||
|
<property name="receives_default">True</property>
|
||||||
|
<signal name="clicked" handler="on_btnZero_clicked"/>
|
||||||
|
</object>
|
||||||
|
<packing>
|
||||||
|
<property name="left_attach">1</property>
|
||||||
|
<property name="right_attach">2</property>
|
||||||
|
<property name="top_attach">3</property>
|
||||||
|
<property name="bottom_attach">4</property>
|
||||||
|
</packing>
|
||||||
|
</child>
|
||||||
|
<child>
|
||||||
|
<object class="GtkButton" id="btnThree">
|
||||||
|
<property name="label" translatable="yes">3</property>
|
||||||
|
<property name="visible">True</property>
|
||||||
|
<property name="can_focus">True</property>
|
||||||
|
<property name="receives_default">True</property>
|
||||||
|
<signal name="clicked" handler="on_btnThree_clicked"/>
|
||||||
|
</object>
|
||||||
|
<packing>
|
||||||
|
<property name="left_attach">2</property>
|
||||||
|
<property name="right_attach">3</property>
|
||||||
|
</packing>
|
||||||
|
</child>
|
||||||
|
<child>
|
||||||
|
<object class="GtkButton" id="btnSix">
|
||||||
|
<property name="label" translatable="yes">6</property>
|
||||||
|
<property name="visible">True</property>
|
||||||
|
<property name="can_focus">True</property>
|
||||||
|
<property name="receives_default">True</property>
|
||||||
|
<signal name="clicked" handler="on_btnSix_clicked"/>
|
||||||
|
</object>
|
||||||
|
<packing>
|
||||||
|
<property name="left_attach">2</property>
|
||||||
|
<property name="right_attach">3</property>
|
||||||
|
<property name="top_attach">1</property>
|
||||||
|
<property name="bottom_attach">2</property>
|
||||||
|
</packing>
|
||||||
|
</child>
|
||||||
|
<child>
|
||||||
|
<object class="GtkButton" id="btnNine">
|
||||||
|
<property name="label" translatable="yes">9</property>
|
||||||
|
<property name="visible">True</property>
|
||||||
|
<property name="can_focus">True</property>
|
||||||
|
<property name="receives_default">True</property>
|
||||||
|
<signal name="clicked" handler="on_btnNine_clicked"/>
|
||||||
|
</object>
|
||||||
|
<packing>
|
||||||
|
<property name="left_attach">2</property>
|
||||||
|
<property name="right_attach">3</property>
|
||||||
|
<property name="top_attach">2</property>
|
||||||
|
<property name="bottom_attach">3</property>
|
||||||
|
</packing>
|
||||||
|
</child>
|
||||||
|
<child>
|
||||||
|
<object class="GtkButton" id="btnOk">
|
||||||
|
<property name="label">Ok</property>
|
||||||
|
<property name="visible">True</property>
|
||||||
|
<property name="can_focus">True</property>
|
||||||
|
<property name="receives_default">True</property>
|
||||||
|
<signal name="clicked" handler="on_btnOk_clicked"/>
|
||||||
|
</object>
|
||||||
|
<packing>
|
||||||
|
<property name="left_attach">2</property>
|
||||||
|
<property name="right_attach">3</property>
|
||||||
|
<property name="top_attach">3</property>
|
||||||
|
<property name="bottom_attach">4</property>
|
||||||
|
</packing>
|
||||||
|
</child>
|
||||||
|
</object>
|
||||||
|
<packing>
|
||||||
|
<property name="position">5</property>
|
||||||
|
</packing>
|
||||||
|
</child>
|
||||||
|
</object>
|
||||||
|
</child>
|
||||||
|
</object>
|
||||||
|
</interface>
|
||||||
Reference in New Issue
Block a user