source: murachi/esteidfirefoxplugin/firefox/dialogs-gtk.c @ 56bf39a

Last change on this file since 56bf39a was 7d3ae3e, checked in by antonioaraujob <aaraujo@…>, 9 years ago

Agregados archivos fuentes del complemento esteidfirefoxplugin de Estonia para firmar electrónicamente un hash.

  • Property mode set to 100644
File size: 13.7 KB
Line 
1/*
2 * Estonian ID card plugin for web browsers
3 *
4 * Copyright (C) 2010-2011 Codeborne <info@codeborne.com>
5 *
6 * This is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU Lesser General Public
8 * License as published by the Free Software Foundation; either
9 * version 2.1 of the License, or (at your option) any later version.
10 *
11 * This software is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
14 * Lesser General Public License for more details.
15 *
16 * You should have received a copy of the GNU Lesser General Public
17 * License along with this library; if not, write to the Free Software
18 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
19 *
20 */
21
22#include <stdlib.h>
23#include <stdio.h>
24#include <string.h>
25#include <gtk/gtk.h>
26#include <gdk/gdkx.h>
27#include <gdk/gdkkeysyms.h>
28
29#include <gdk/gdk.h>
30#include "dialogs.h"
31#include "esteid_log.h"
32#include "l10n.h"
33#include "esteid_map.h"
34#include "esteid_certinfo.h"
35#include "esteid_time.h"
36#include "esteid_dialog_common.h"
37
38GtkWidget *dialog;
39GtkWidget* progressBar;
40int timeoutCounter;
41guint timerID;
42
43typedef struct {
44  GtkWidget* button;
45  unsigned minPin2Length;
46} EstEID_PIN2LengthControlData;
47
48void setDialogProperties(GtkWidget *dialog, GtkWidget *window) {
49  gtk_container_set_border_width(GTK_CONTAINER(dialog), 5);
50  gtk_window_set_transient_for(GTK_WINDOW(dialog), GTK_WINDOW(window));
51  gtk_window_set_modal(GTK_WINDOW(dialog), TRUE);
52  gtk_dialog_set_default_response(GTK_DIALOG(dialog), GTK_RESPONSE_OK);
53  gtk_window_set_resizable(GTK_WINDOW(dialog), FALSE);
54  gtk_window_set_urgency_hint(GTK_WINDOW(dialog), TRUE);
55}
56
57static void enableButtonWhenPINLengthIsCorrect(GtkWidget* entry, EstEID_PIN2LengthControlData* pin2LengthControl) {
58  gtk_widget_set_sensitive(GTK_WIDGET(pin2LengthControl->button), gtk_entry_get_text_length(GTK_ENTRY(entry)) >= pin2LengthControl->minPin2Length);
59}
60
61GtkWidget *createPIN2Dialog(GtkWidget *window, GtkWidget *entry, const char *nameAndID, const char *message, const unsigned minPin2Length) {
62  dialog = gtk_dialog_new_with_buttons(createDialogTitle(nameAndID), GTK_WINDOW(window),
63      GTK_DIALOG_DESTROY_WITH_PARENT,
64      NULL);
65
66  gtk_dialog_add_button((GtkDialog*) dialog, (const gchar*) l10n("Cancel"), GTK_RESPONSE_CANCEL);
67  GtkWidget* signButton = gtk_dialog_add_button((GtkDialog*) dialog, (const gchar*) l10n("Sign"), GTK_RESPONSE_OK);
68  gtk_widget_set_sensitive(signButton, FALSE);
69
70  setDialogProperties(dialog, window);
71
72  GtkWidget* vbox = gtk_vbox_new(FALSE, 12);
73
74  if (message && message[0]) {
75    GtkWidget *messageLabel = gtk_label_new(NULL);
76    char *markup = g_markup_printf_escaped("<span color='red'>%s</span>", message);
77    gtk_label_set_markup(GTK_LABEL(messageLabel), markup);
78    free(markup);
79    gtk_container_add(GTK_CONTAINER(vbox), messageLabel);
80  }
81  GtkWidget *nameLabel = gtk_label_new(nameAndID);
82  gtk_container_add(GTK_CONTAINER(vbox), nameLabel);
83  gtk_misc_set_alignment(GTK_MISC(nameLabel), 0.0, 0.0);
84
85  GtkWidget* hbox = gtk_hbox_new(FALSE, 12);
86
87  EstEID_PIN2LengthControlData* pin2LengthControl;
88  pin2LengthControl = g_new0(EstEID_PIN2LengthControlData, 1);
89  pin2LengthControl->button = signButton;
90  pin2LengthControl->minPin2Length = minPin2Length;
91
92  g_signal_connect(G_OBJECT(entry), "changed", G_CALLBACK(enableButtonWhenPINLengthIsCorrect), (gpointer) pin2LengthControl);
93  gtk_entry_set_visibility(GTK_ENTRY(entry), FALSE);
94  gtk_entry_set_max_length(GTK_ENTRY(entry), 12);
95  gtk_entry_set_activates_default(GTK_ENTRY(entry), TRUE);
96
97  GtkWidget *label = gtk_label_new(l10n("For signing enter PIN2:"));
98  gtk_label_set_use_underline(GTK_LABEL(label), TRUE);
99  gtk_label_set_mnemonic_widget(GTK_LABEL(label), entry);
100
101  gtk_container_add(GTK_CONTAINER(hbox), label);
102  gtk_container_add(GTK_CONTAINER(hbox), entry);
103
104  gtk_container_add(GTK_CONTAINER(vbox), hbox);
105  gtk_container_set_border_width(GTK_CONTAINER(vbox), 5);
106
107  gtk_container_add(GTK_CONTAINER(GTK_DIALOG(dialog)->vbox), vbox);
108  gtk_dialog_set_has_separator(GTK_DIALOG(dialog), FALSE);
109
110  gtk_container_set_border_width(GTK_CONTAINER(dialog), 5);
111
112  g_signal_connect(G_OBJECT(dialog), "destroy", G_CALLBACK(gtk_main_quit), NULL);
113
114  gtk_widget_show_all(dialog);
115  return dialog;
116}
117
118gint keyHandler(GtkWidget *window, GdkEventKey *key) {
119  LOG_LOCATION;
120  return TRUE;
121}
122
123static gboolean closingPreventionHandler(GtkWidget *window, GdkEvent *event, gpointer data) {
124  LOG_LOCATION;
125  EstEID_log("preventing to close widget %s", gtk_widget_get_name(GTK_WIDGET(window)));
126  return TRUE;
127}
128
129GtkWidget *createPINPadDialog(GtkWidget *window, const char *nameAndID, const char *message) {
130  LOG_LOCATION;
131  dialog = gtk_dialog_new_with_buttons(createDialogTitle(nameAndID), GTK_WINDOW(window),
132      GTK_DIALOG_DESTROY_WITH_PARENT, NULL);
133
134  setDialogProperties(dialog, window);
135
136  GtkWidget* vbox = gtk_vbox_new(FALSE, 12);
137
138  if (message && message[0]) {
139    GtkWidget* messageLabel = gtk_label_new(NULL);
140    char* markup = g_markup_printf_escaped("<span color='red'>%s</span>", message);
141    gtk_label_set_markup(GTK_LABEL(messageLabel), markup);
142    free(markup);
143    gtk_container_add(GTK_CONTAINER(vbox), messageLabel);
144  }
145  GtkWidget *nameLabel = gtk_label_new(nameAndID);
146  gtk_container_add(GTK_CONTAINER(vbox), nameLabel);
147  gtk_misc_set_alignment(GTK_MISC(nameLabel), 0.0, 0.0);
148
149  GtkWidget* hbox = gtk_hbox_new(FALSE, 12);
150
151  GtkWidget* label = gtk_label_new(l10n("For signing enter PIN2 from PIN pad"));
152  gtk_label_set_use_underline(GTK_LABEL(label), TRUE);
153
154  progressBar = gtk_progress_bar_new();
155  gtk_progress_bar_set_fraction(GTK_PROGRESS_BAR(progressBar), (gdouble) 1.0);
156
157  gtk_container_add(GTK_CONTAINER(hbox), label);
158
159  gtk_container_add(GTK_CONTAINER(vbox), hbox);
160  gtk_container_add(GTK_CONTAINER(vbox), progressBar);
161  gtk_container_set_border_width(GTK_CONTAINER(vbox), 5);
162
163  gtk_container_add(GTK_CONTAINER(GTK_DIALOG(dialog)->vbox), vbox);
164  gtk_dialog_set_has_separator(GTK_DIALOG(dialog), FALSE);
165
166  gtk_container_set_border_width(GTK_CONTAINER(dialog), 5);
167
168  g_signal_connect(G_OBJECT(dialog), "key_press_event", G_CALLBACK(keyHandler), NULL);
169  g_signal_connect(G_OBJECT(dialog), "delete-event", G_CALLBACK(closingPreventionHandler), NULL);
170  g_signal_connect(G_OBJECT(dialog), "destroy", G_CALLBACK(gtk_main_quit), NULL);
171
172  gtk_widget_show_all(dialog);
173  return dialog;
174}
175
176GtkWidget *getGtkWindow(void *nativeWindowHandle) {
177  GdkWindow *p = (GdkWindow *) gdk_window_lookup((XID) nativeWindowHandle);
178  GtkWidget *window = NULL;
179  gdk_window_get_user_data(p, (gpointer *) & window);
180  return window;
181}
182
183void showAlert(void *nativeWindowHandle, const char *message) {
184  GtkWidget *window = getGtkWindow(nativeWindowHandle);
185  GtkWidget *alertDialog = gtk_message_dialog_new(GTK_WINDOW(window), GTK_DIALOG_DESTROY_WITH_PARENT, GTK_MESSAGE_ERROR, GTK_BUTTONS_CLOSE, message, "");
186  gtk_window_set_title(GTK_WINDOW(alertDialog), l10n("Error"));
187  gtk_dialog_run(GTK_DIALOG(alertDialog));
188  gtk_widget_destroy(alertDialog);
189}
190
191void killCountdownTimer() {
192  if (timerID) {
193    if (g_source_remove(timerID)) {
194      EstEID_log("killed timer %u", timerID);
195    }
196    else {
197      EstEID_log("unable to kill timer %u (probably dead already)", timerID);
198    }
199    timerID = 0;
200  }
201}
202
203static gboolean updateCountdownProgressBar() {
204  --timeoutCounter;
205  if (timeoutCounter <= 0) {
206    EstEID_log("countdown reached 0, killing timer by returning FALSE from callback");
207    timerID = 0;
208    return FALSE;
209  }
210  gtk_progress_bar_set_fraction(GTK_PROGRESS_BAR(progressBar), (gdouble) timeoutCounter / (gdouble) 30);
211  return TRUE;
212}
213
214char *promptForPIN(void *nativeWindowHandle, const char *name, const char *message, unsigned minPin2Length, int usePinPad) {
215  LOG_LOCATION;
216  GtkWidget *window = getGtkWindow(nativeWindowHandle);
217  GtkWidget *entry = gtk_entry_new();
218  char *pin;
219
220  if (!usePinPad) {
221    // Simple card reader
222    dialog = createPIN2Dialog(window, entry, name, message, minPin2Length);
223
224    gint result = gtk_dialog_run(GTK_DIALOG(dialog));
225    gtk_widget_hide(dialog);
226    if (result == GTK_RESPONSE_OK) {
227      pin = strdup(gtk_entry_get_text(GTK_ENTRY(entry)));
228      EstEID_log("promptForPIN\t got pin");
229    }
230    else {
231      pin = strdup("");
232      EstEID_log("promptForPIN\t user canceled");
233    }
234  }
235  else {
236    // PIN pad
237    killCountdownTimer();
238    timeoutCounter = 30;
239    EstEID_log("timeoutCounter value set to %i", timeoutCounter);
240    dialog = createPINPadDialog(window, name, message);
241    g_signal_connect(G_OBJECT(dialog), "destroy", G_CALLBACK(updateCountdownProgressBar), NULL);
242    timerID = g_timeout_add_seconds(1, (GSourceFunc) updateCountdownProgressBar, NULL);
243    EstEID_log("created timer %u", timerID);
244    gtk_dialog_run(GTK_DIALOG(dialog));
245    pin = strdup("");
246  }
247
248  return pin;
249}
250
251static GtkTreeModel* createAndFillModel() {
252  GtkListStore *certificatesList = gtk_list_store_new(4, G_TYPE_STRING, G_TYPE_STRING, G_TYPE_STRING, G_TYPE_STRING);
253  GtkTreeIter iterator;
254  char *validTo = NULL;
255
256  EstEID_Certs *certs = EstEID_loadCerts();
257  EstEID_log("%i certificates found", certs->count);
258  for (int i = 0; i < certs->count; i++) {
259    EstEID_Map cert = certs->certs[i];
260    if (!EstEID_mapGet(cert, "usageNonRepudiation")) continue;
261
262    validTo = getDateFromDateTime(EstEID_mapGet(cert, "validTo"));
263
264    gtk_list_store_append(certificatesList, &iterator);
265    gtk_list_store_set(certificatesList, &iterator,
266        0, EstEID_mapGet(cert, "commonName"),
267        1, EstEID_mapGet(cert, "organizationName"),
268        2, validTo,
269        3, EstEID_mapGet(cert, "certHash"),
270        -1);
271    if (validTo) {
272      free(validTo);
273      validTo = NULL;
274    }
275  }
276  return GTK_TREE_MODEL(certificatesList);
277}
278
279static void selectionFunction(GtkTreeSelection* selection, GtkDialog* dialog) {
280  gtk_dialog_set_response_sensitive(dialog, GTK_RESPONSE_OK, gtk_tree_selection_count_selected_rows(selection) > 0);
281}
282
283static void doubleClick(GtkTreeView* treeView, GtkTreePath* path, GtkTreeViewColumn *col, GtkDialog* dialog) {
284  gtk_dialog_response(dialog, GTK_RESPONSE_OK);
285}
286
287GtkWidget *createCertificateSelectionView(GtkWidget *window) {
288  GtkWidget* certificatesView = gtk_tree_view_new();
289
290  gtk_widget_set_size_request(certificatesView, 400, 200);
291
292  GtkCellRenderer* renderer;
293
294  renderer = gtk_cell_renderer_text_new();
295
296  GtkTreeViewColumn* col1 = gtk_tree_view_column_new_with_attributes(l10n("Certificate"), renderer, "text", 0, NULL);
297  col1->expand = TRUE;
298  gtk_tree_view_append_column(GTK_TREE_VIEW(certificatesView), col1);
299
300  renderer = gtk_cell_renderer_text_new();
301  gtk_tree_view_insert_column_with_attributes(GTK_TREE_VIEW(certificatesView), -1, l10n("Type"), renderer, "text", 1, NULL);
302
303  renderer = gtk_cell_renderer_text_new();
304  gtk_tree_view_insert_column_with_attributes(GTK_TREE_VIEW(certificatesView), -1, l10n("Valid to"), renderer, "text", 2, NULL);
305
306  gtk_tree_view_set_headers_visible(GTK_TREE_VIEW(certificatesView), TRUE);
307  GtkTreeModel* model = createAndFillModel();
308
309  gtk_tree_view_set_model(GTK_TREE_VIEW(certificatesView), model);
310
311  GtkTreeSelection* selection = gtk_tree_view_get_selection(GTK_TREE_VIEW(certificatesView));
312  GtkTreeIter iter;
313  if (gtk_tree_model_get_iter_first(model, &iter)) {
314    gtk_tree_selection_select_iter(selection, &iter);
315    selectionFunction(selection, GTK_DIALOG(window));
316  }
317
318  g_signal_connect(G_OBJECT(selection), "changed", G_CALLBACK(selectionFunction), GTK_DIALOG(window));
319  g_signal_connect(G_OBJECT(certificatesView), "row-activated", G_CALLBACK(doubleClick), GTK_DIALOG(window));
320
321  return certificatesView;
322}
323
324int promptForCertificate(void *nativeWindowHandle, char* certId) {
325  certId[0] = '\0';
326
327  GtkWidget *window = getGtkWindow(nativeWindowHandle);
328  dialog = gtk_dialog_new_with_buttons(l10n("Select certificate"), GTK_WINDOW(window), // ToDo l10n
329      GTK_DIALOG_DESTROY_WITH_PARENT,
330      NULL);
331
332  gtk_dialog_add_button((GtkDialog*) dialog, (const gchar*) l10n("Cancel"), GTK_RESPONSE_CANCEL);
333  gtk_dialog_add_button((GtkDialog*) dialog, (const gchar*) l10n("Select"), GTK_RESPONSE_OK);
334
335  gtk_dialog_set_response_sensitive(GTK_DIALOG(dialog), GTK_RESPONSE_OK, FALSE);
336
337  GtkWidget *warningLabel = gtk_label_new((const gchar*) l10n("By selecting a certificate I accept that my name and personal ID code will be sent to service provider."));
338  GtkWidget* vbox = gtk_vbox_new(FALSE, 12);
339  gtk_container_set_border_width(GTK_CONTAINER(vbox), 10);
340  gtk_container_add(GTK_CONTAINER(vbox), warningLabel);
341  gtk_container_add(GTK_CONTAINER(GTK_DIALOG(dialog)->vbox), vbox);
342
343  GtkWidget* certificatesView = createCertificateSelectionView(dialog);
344
345  gtk_container_add(GTK_CONTAINER(GTK_DIALOG(dialog)->vbox), certificatesView);
346
347  setDialogProperties(dialog, window);
348  gtk_dialog_set_has_separator(GTK_DIALOG(dialog), FALSE);
349  gtk_widget_show_all(dialog);
350
351  gint result = gtk_dialog_run(GTK_DIALOG(dialog));
352
353  gtk_widget_hide(dialog);
354
355  int returnValue = IDCANCEL;
356  if (result == GTK_RESPONSE_OK) {
357    GtkTreeSelection* selectedRow = gtk_tree_view_get_selection(GTK_TREE_VIEW(certificatesView));
358    GtkTreeModel* model = NULL;
359    GtkTreeIter iter;
360    if (gtk_tree_selection_get_selected(selectedRow, &model, &iter)) {
361      gchar* id;
362      gtk_tree_model_get(model, &iter, 3, &id, -1);
363      strcpy(certId, id);
364      g_free(id);
365      returnValue = IDOK;
366      EstEID_log("promptForCertificate dialog returned cert ID %s", certId);
367    }
368    else {
369      EstEID_log("promptForCertificate dialog returned without cert selection");
370    }
371  }
372  else {
373    EstEID_log("promptForCertificate dialog canceled by user");
374  }
375  gtk_widget_destroy(dialog);
376  return returnValue;
377}
378
379void closePinPadModalSheet() {
380  LOG_LOCATION;
381  killCountdownTimer();
382  gtk_widget_destroy(dialog);
383}
Note: See TracBrowser for help on using the repository browser.