[network-manager-applet/lr/pkcs11: 7/9] WIP libnma: add a file certificate chooser



commit 089bd88019fc42cb005195b2e04df36e1dabcaf7
Author: Lubomir Rintel <lkundrak v3 sk>
Date:   Wed Feb 22 18:43:53 2017 +0100

    WIP libnma: add a file certificate chooser

 Makefile.am                        |    6 +-
 src/libnma/libnma.ver              |    1 +
 src/libnma/nma-cert-chooser.c      |    6 +-
 src/libnma/nma-cert-file-chooser.c |  404 ++++++++++++++++++++++++++++++++++++
 src/libnma/nma-cert-file-chooser.h |   48 +++++
 5 files changed, 462 insertions(+), 3 deletions(-)
---
diff --git a/Makefile.am b/Makefile.am
index 4056095..7e4f29f 100644
--- a/Makefile.am
+++ b/Makefile.am
@@ -477,7 +477,8 @@ libnma_h_pub = \
        src/libnma/nma-mobile-providers.h \
        src/libnma/nma-vpn-password-dialog.h \
        src/libnma/nma-ui-utils.h \
-       src/libnma/nma-cert-chooser.h
+       src/libnma/nma-cert-chooser.h \
+       src/libnma/nma-cert-file-chooser.h
 
 libnma_c_real = \
        src/libnma/nma-wifi-dialog.c \
@@ -486,7 +487,8 @@ libnma_c_real = \
        src/libnma/nma-vpn-password-dialog.c \
        src/libnma/nma-ui-utils.c \
        src/libnma/init.c \
-       src/libnma/nma-cert-chooser.c
+       src/libnma/nma-cert-chooser.c \
+       src/libnma/nma-cert-file-chooser.c
 
 src_libnma_libnmadir = $(includedir)/libnma
 
diff --git a/src/libnma/libnma.ver b/src/libnma/libnma.ver
index f03d71b..f31ae99 100644
--- a/src/libnma/libnma.ver
+++ b/src/libnma/libnma.ver
@@ -83,4 +83,5 @@ global:
        nma_cert_chooser_set_key_password;
        nma_cert_chooser_get_key_password;
        nma_cert_chooser_new;
+       nma_cert_file_chooser_get_type;
 } libnma_1_2_0;
diff --git a/src/libnma/nma-cert-chooser.c b/src/libnma/nma-cert-chooser.c
index 0a3ce0e..44b8260 100644
--- a/src/libnma/nma-cert-chooser.c
+++ b/src/libnma/nma-cert-chooser.c
@@ -28,6 +28,7 @@
 #include <errno.h>
 
 #include "nma-cert-chooser.h"
+#include "nma-cert-file-chooser.h"
 
 enum {
        CERT_CHANGED,
@@ -280,5 +281,8 @@ nma_cert_chooser_add_to_size_group (NMACertChooser *cert_chooser, GtkSizeGroup *
 GtkWidget *
 nma_cert_chooser_new (const gchar *title, NMACertChooserFlags flags)
 {
-       g_return_val_if_reached (NULL);
+       if (flags & NMA_CERT_CHOOSER_FLAG_PEM)
+               return nma_cert_file_chooser_new (title, flags);
+
+       return nma_cert_file_chooser_new (title, flags);
 }
diff --git a/src/libnma/nma-cert-file-chooser.c b/src/libnma/nma-cert-file-chooser.c
new file mode 100644
index 0000000..55988a7
--- /dev/null
+++ b/src/libnma/nma-cert-file-chooser.c
@@ -0,0 +1,404 @@
+/*
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301 USA.
+ *
+ * Copyright (C) 2015,2017 Red Hat, Inc.
+ */
+
+#include <config.h>
+
+#include <glib/gi18n-lib.h>
+#include <glib/gstdio.h>
+#include <gtk/gtk.h>
+
+#include <sys/stat.h>
+#include <fcntl.h>
+#include <errno.h>
+
+#include "nm-default.h"
+#include "nma-cert-file-chooser.h"
+#include "utils.h"
+
+void nma_cert_chooser_interface_init (NMACertChooserInterface *iface);
+
+typedef struct {
+       GtkWidget *key_button_label;
+       GtkWidget *key_password_label;
+       GtkWidget *cert_button_label;
+       GtkWidget *key_button;
+       GtkWidget *key_password;
+       GtkWidget *cert_button;
+} NMACertFileChooserPrivate;
+
+#define NMA_CERT_FILE_CHOOSER_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE ((o), NMA_TYPE_CERT_FILE_CHOOSER, 
NMACertFileChooserPrivate))
+
+G_DEFINE_TYPE_WITH_CODE (NMACertFileChooser, nma_cert_file_chooser, GTK_TYPE_GRID,
+                         G_IMPLEMENT_INTERFACE (NMA_TYPE_CERT_CHOOSER,
+                                                nma_cert_chooser_interface_init))
+
+static gboolean
+file_has_extension (const char *filename, const char *extensions[])
+{
+       char *p, *ext;
+       int i = 0;
+       gboolean found = FALSE;
+
+       p = strrchr (filename, '.');
+       if (!p)
+               return FALSE;
+
+       ext = g_ascii_strdown (p, -1);
+       if (ext) {
+               while (extensions[i]) {
+                       if (!strcmp (ext, extensions[i++])) {
+                               found = TRUE;
+                               break;
+                       }
+               }
+       }
+       g_free (ext);
+
+       return found;
+}
+
+static gboolean
+cert_filter (const GtkFileFilterInfo *filter_info, gpointer data)
+{
+       const char *extensions[] = { ".der", ".pem", ".crt", ".cer", ".p12", NULL };
+
+       if (!filter_info->filename)
+               return FALSE;
+
+       if (!file_has_extension (filter_info->filename, extensions))
+               return FALSE;
+
+       return TRUE;
+}
+
+static gboolean
+privkey_filter (const GtkFileFilterInfo *filter_info, gpointer user_data)
+{
+       const char *extensions[] = { ".der", ".pem", ".p12", ".key", NULL };
+
+       if (!filter_info->filename)
+               return FALSE;
+
+       if (!file_has_extension (filter_info->filename, extensions))
+               return FALSE;
+
+       return TRUE;
+}
+
+static void
+key_password_changed (NMACertChooser *cert_chooser)
+{
+       NMACertFileChooserPrivate *priv = NMA_CERT_FILE_CHOOSER_GET_PRIVATE (cert_chooser);
+       gboolean invalid = FALSE;
+
+       g_signal_emit_by_name (cert_chooser, "key-password-changed", &invalid);
+       if (invalid)
+               widget_set_error (priv->key_password);
+       else
+               widget_unset_error (priv->key_password);
+       g_signal_emit_by_name (cert_chooser, "changed");
+}
+
+static void
+key_password_changed_cb (GtkEditable *editable, gpointer user_data)
+{
+       key_password_changed (NMA_CERT_CHOOSER (user_data));
+}
+
+static void
+set_key_password (NMACertChooser *cert_chooser, const gchar *password)
+{
+       NMACertFileChooserPrivate *priv = NMA_CERT_FILE_CHOOSER_GET_PRIVATE (cert_chooser);
+
+       g_return_if_fail (priv->key_password != NULL);
+       gtk_entry_set_text (GTK_ENTRY (priv->key_password), password);
+       key_password_changed (cert_chooser);
+}
+
+static const gchar *
+get_key_password (NMACertChooser *cert_chooser)
+{
+       NMACertFileChooserPrivate *priv = NMA_CERT_FILE_CHOOSER_GET_PRIVATE (cert_chooser);
+
+       g_return_val_if_fail (priv->key_password != NULL, NULL);
+       return gtk_entry_get_text (GTK_ENTRY (priv->key_password));
+}
+
+
+static void
+key_changed (NMACertChooser *cert_chooser)
+{
+       NMACertFileChooserPrivate *priv = NMA_CERT_FILE_CHOOSER_GET_PRIVATE (cert_chooser);
+       gboolean invalid = FALSE;
+
+       g_signal_emit_by_name (cert_chooser, "key-changed", &invalid);
+       if (invalid) {
+               widget_set_error (priv->key_button);
+       } else {
+               widget_unset_error (priv->key_button);
+               gtk_widget_set_sensitive (priv->key_password, TRUE);
+               gtk_widget_set_sensitive (priv->key_password_label, TRUE);
+               key_password_changed (cert_chooser);
+       }
+       g_signal_emit_by_name (cert_chooser, "changed");
+}
+
+static void
+key_selection_changed_cb (GtkFileChooser *file_chooser, gpointer user_data)
+{
+       key_changed (NMA_CERT_CHOOSER (user_data));
+}
+
+static void
+set_key (NMACertChooser *cert_chooser, const gchar *value, NMSetting8021xCKScheme scheme)
+{
+       NMACertFileChooserPrivate *priv = NMA_CERT_FILE_CHOOSER_GET_PRIVATE (cert_chooser);
+
+       if (value) {
+               if (scheme != NM_SETTING_802_1X_CK_SCHEME_PATH) {
+                       g_warning ("The key '%s' uses an unknown scheme %d\n", value, scheme);
+                       return;
+               }
+               gtk_file_chooser_set_filename (GTK_FILE_CHOOSER (priv->key_button), value);
+       }
+       key_changed (cert_chooser);
+}
+
+static gchar *
+get_key (NMACertChooser *cert_chooser, NMSetting8021xCKScheme *scheme)
+{
+       NMACertFileChooserPrivate *priv = NMA_CERT_FILE_CHOOSER_GET_PRIVATE (cert_chooser);
+
+       g_return_val_if_fail (scheme != NULL, NULL);
+       g_return_val_if_fail (priv->key_button != NULL, NULL);
+       *scheme = NM_SETTING_802_1X_CK_SCHEME_PATH;
+       return gtk_file_chooser_get_filename (GTK_FILE_CHOOSER (priv->key_button));
+}
+
+static void
+cert_changed (NMACertChooser *cert_chooser)
+{
+       NMACertFileChooserPrivate *priv = NMA_CERT_FILE_CHOOSER_GET_PRIVATE (cert_chooser);
+       gboolean invalid = FALSE;
+
+       g_signal_emit_by_name (cert_chooser, "cert-changed", &invalid);
+       if (invalid) {
+               widget_set_error (priv->cert_button);
+       } else {
+               widget_unset_error (priv->cert_button);
+               if (priv->key_button) {
+                       gtk_widget_set_sensitive (priv->key_button, TRUE);
+                       gtk_widget_set_sensitive (priv->key_button_label, TRUE);
+                       key_changed (cert_chooser);
+               }
+       }
+       g_signal_emit_by_name (cert_chooser, "changed");
+}
+
+static void
+cert_selection_changed_cb (GtkFileChooser *file_chooser, gpointer user_data)
+{
+       cert_changed (NMA_CERT_CHOOSER (user_data));
+}
+
+static void
+set_cert (NMACertChooser *cert_chooser, const gchar *value, NMSetting8021xCKScheme scheme)
+{
+       NMACertFileChooserPrivate *priv = NMA_CERT_FILE_CHOOSER_GET_PRIVATE (cert_chooser);
+
+       if (value) {
+               if (scheme != NM_SETTING_802_1X_CK_SCHEME_PATH) {
+                       g_warning ("The certificate '%s' uses an unknown scheme %d\n", value, scheme);
+                       return;
+               }
+               gtk_file_chooser_set_filename (GTK_FILE_CHOOSER (priv->cert_button), value);
+       }
+       cert_changed (cert_chooser);
+}
+
+static gchar *
+get_cert (NMACertChooser *cert_chooser, NMSetting8021xCKScheme *scheme)
+{
+       NMACertFileChooserPrivate *priv = NMA_CERT_FILE_CHOOSER_GET_PRIVATE (cert_chooser);
+
+       g_return_val_if_fail (scheme != NULL, NULL);
+       *scheme = NM_SETTING_802_1X_CK_SCHEME_PATH;
+       return gtk_file_chooser_get_filename (GTK_FILE_CHOOSER (priv->cert_button));
+}
+
+
+static void
+add_to_size_group (NMACertChooser *cert_chooser, GtkSizeGroup *group)
+{
+       NMACertFileChooserPrivate *priv = NMA_CERT_FILE_CHOOSER_GET_PRIVATE (cert_chooser);
+
+       gtk_size_group_add_widget (group, priv->cert_button_label);
+       if (priv->key_button_label)
+               gtk_size_group_add_widget (group, priv->key_button_label);
+       if (priv->key_password_label)
+               gtk_size_group_add_widget (group, priv->key_password_label);
+}
+
+void
+nma_cert_chooser_interface_init (NMACertChooserInterface *iface)
+{
+       iface->set_cert = set_cert;
+       iface->get_cert = get_cert;
+       iface->set_key = set_key;
+       iface->get_key = get_key;
+       iface->set_key_password = set_key_password;
+       iface->get_key_password = get_key_password;
+
+       iface->add_to_size_group = add_to_size_group;
+}
+
+static void
+reset_filter (GtkWidget *widget, GParamSpec *spec, gpointer user_data)
+{
+       if (!gtk_file_chooser_get_filter (GTK_FILE_CHOOSER (widget))) {
+               g_signal_handlers_block_by_func (widget, reset_filter, user_data);
+               gtk_file_chooser_set_filter (GTK_FILE_CHOOSER (widget), GTK_FILE_FILTER (user_data));
+               g_signal_handlers_unblock_by_func (widget, reset_filter, user_data);
+       }
+}
+
+GtkWidget *
+nma_cert_file_chooser_new (const gchar *title, NMACertChooserFlags flags)
+{
+       GtkWidget *self;
+       NMACertFileChooserPrivate *priv;
+       GtkFileFilter *filter;
+       gchar *text;
+
+       self = g_object_new (NMA_TYPE_CERT_FILE_CHOOSER, NULL);
+       priv = NMA_CERT_FILE_CHOOSER_GET_PRIVATE (self);
+
+       gtk_grid_insert_column (GTK_GRID (self), 2);
+       gtk_grid_set_row_spacing (GTK_GRID (self), 6);
+       gtk_grid_set_column_spacing (GTK_GRID (self), 12);
+
+       if ((flags & NMA_CERT_CHOOSER_FLAG_CERT) == 0) {
+               /* The key password entry */
+               gtk_grid_insert_row (GTK_GRID (self), 0);
+
+               priv->key_password = gtk_entry_new ();
+               gtk_entry_set_visibility (GTK_ENTRY (priv->key_password), FALSE);
+               gtk_grid_attach (GTK_GRID (self), priv->key_password, 1, 0, 1, 1);
+               gtk_widget_set_hexpand (priv->key_password, TRUE);
+               gtk_widget_set_sensitive (priv->key_password, FALSE);
+               gtk_widget_show (priv->key_password);
+
+               g_signal_connect (priv->key_password, "changed",
+                                 G_CALLBACK (key_password_changed_cb), self);
+
+               text = g_strdup_printf (_("%s key password:"), title);
+               priv->key_password_label = gtk_label_new (text);
+               gtk_label_set_xalign (GTK_LABEL (priv->key_password_label), 0);
+               gtk_label_set_mnemonic_widget (GTK_LABEL (priv->key_password_label), priv->key_password);
+               gtk_grid_attach (GTK_GRID (self), priv->key_password_label, 0, 0, 1, 1);
+               gtk_widget_set_sensitive (priv->key_password_label, FALSE);
+               gtk_widget_show (priv->key_password_label);
+               g_free (text);
+
+               /* The key chooser */
+               gtk_grid_insert_row (GTK_GRID (self), 0);
+
+               filter = gtk_file_filter_new ();
+               gtk_file_filter_add_custom (filter, GTK_FILE_FILTER_FILENAME, privkey_filter, NULL, NULL);
+               gtk_file_filter_set_name (filter, _("DER, PEM, or PKCS#12 private keys (*.der, *.pem, *.p12, 
*.key)"));
+
+               text = g_strdup_printf (_("Choose a key for %s"), title);
+               priv->key_button = g_object_new (GTK_TYPE_FILE_CHOOSER_BUTTON,
+                                                 "action", GTK_FILE_CHOOSER_ACTION_OPEN,
+                                                 "title", text,
+                                                 "filter", filter,
+                                                 "local-only", TRUE,
+                                                 NULL);
+               g_free (text);
+               gtk_grid_attach (GTK_GRID (self), priv->key_button, 1, 0, 1, 1);
+               gtk_widget_set_hexpand (priv->key_button, TRUE);
+               gtk_widget_set_sensitive (priv->key_button, FALSE);
+               gtk_widget_show (priv->key_button);
+
+               g_signal_connect (priv->key_button, "selection-changed",
+                                 G_CALLBACK (key_selection_changed_cb), self);
+
+               text = g_strdup_printf (_("%s key:"), title);
+               priv->key_button_label = gtk_label_new (text);
+               gtk_label_set_xalign (GTK_LABEL (priv->key_button_label), 0);
+               gtk_label_set_mnemonic_widget (GTK_LABEL (priv->key_button_label), priv->key_button);
+               gtk_grid_attach (GTK_GRID (self), priv->key_button_label, 0, 0, 1, 1);
+               gtk_widget_set_sensitive (priv->key_button_label, FALSE);
+               gtk_widget_show (priv->key_button_label);
+               g_free (text);
+       }
+
+       /* The certificate chooser */
+       gtk_grid_insert_row (GTK_GRID (self), 0);
+
+       filter = gtk_file_filter_new ();
+       gtk_file_filter_add_custom (filter, GTK_FILE_FILTER_FILENAME, cert_filter, NULL, NULL);
+       gtk_file_filter_set_name (filter, _("PEM certificates (*.pem, *.crt, *.cer)"));
+
+       text = g_strdup_printf (_("Choose %s"), title);
+       priv->cert_button = g_object_new (GTK_TYPE_FILE_CHOOSER_BUTTON,
+                                         "action", GTK_FILE_CHOOSER_ACTION_OPEN,
+                                         "title", text,
+                                         "filter", filter,
+                                         "local-only", TRUE,
+                                         NULL);
+       g_free (text);
+       gtk_grid_attach (GTK_GRID (self), priv->cert_button, 1, 0, 1, 1);
+       gtk_widget_set_hexpand (priv->cert_button, TRUE);
+       gtk_widget_show (priv->cert_button);
+
+       /* For some reason, GTK+ calls set_current_filter (..., NULL) from 
+        * gtkfilechooserdefault.c::show_and_select_files_finished_loading() on our
+        * dialog; so force-reset the filter to what we want it to be whenever
+        * it gets cleared.
+        */
+       g_signal_connect (priv->cert_button, "notify::filter",
+                         G_CALLBACK (reset_filter), filter);
+
+       g_signal_connect (priv->cert_button, "selection-changed",
+                         G_CALLBACK (cert_selection_changed_cb), self);
+
+       text = g_strdup_printf (_("%s:"), title);
+       priv->cert_button_label = gtk_label_new (text);
+       gtk_label_set_xalign (GTK_LABEL (priv->cert_button_label), 0);
+       gtk_label_set_mnemonic_widget (GTK_LABEL (priv->cert_button_label), priv->cert_button);
+       gtk_grid_attach (GTK_GRID (self), priv->cert_button_label, 0, 0, 1, 1);
+       gtk_widget_show (priv->cert_button_label);
+       g_free (text);
+
+       return self;
+}
+
+static void
+nma_cert_file_chooser_class_init (NMACertFileChooserClass *klass)
+{
+       GObjectClass *object_class = G_OBJECT_CLASS (klass);
+
+       g_type_class_add_private (object_class, sizeof (NMACertFileChooserPrivate));
+}
+
+static void
+nma_cert_file_chooser_init (NMACertFileChooser *cert_file_chooser)
+{
+}
diff --git a/src/libnma/nma-cert-file-chooser.h b/src/libnma/nma-cert-file-chooser.h
new file mode 100644
index 0000000..a1702f0
--- /dev/null
+++ b/src/libnma/nma-cert-file-chooser.h
@@ -0,0 +1,48 @@
+/* -*- Mode: C; tab-width: 4; indent-tabs-mode: t; c-basic-offset: 4 -*- */
+/*
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301 USA.
+ *
+ * Copyright (C) 2015,2017 Red Hat, Inc.
+ */
+
+#ifndef NMA_CERT_FILE_CHOOSER_H
+#define NMA_CERT_FILE_CHOOSER_H
+
+#include <gtk/gtk.h>
+#include "nma-cert-chooser.h"
+
+G_BEGIN_DECLS
+
+#define NMA_TYPE_CERT_FILE_CHOOSER                   (nma_cert_file_chooser_get_type ())
+#define NMA_CERT_FILE_CHOOSER(obj)                   (G_TYPE_CHECK_INSTANCE_CAST ((obj), 
NMA_TYPE_CERT_FILE_CHOOSER, NMACertChooser))
+#define NMA_IS_CERT_FILE_CHOOSER(obj)                (G_TYPE_CHECK_INSTANCE_TYPE ((obj), 
NMA_TYPE_CERT_FILE_CHOOSER))
+#define NMA_CERT_FILE_CHOOSER_GET_INTERFACE(obj)     (G_TYPE_INSTANCE_GET_INTERFACE ((obj), 
NMA_TYPE_CERT_FILE_CHOOSER, NMACertChooserInterface))
+
+typedef struct {
+       GtkGrid parent;
+} NMACertFileChooser;
+
+typedef struct {
+       GtkGridClass parent_class;
+} NMACertFileChooserClass;
+
+GType nma_cert_file_chooser_get_type (void);
+
+GtkWidget *nma_cert_file_chooser_new (const gchar *title, NMACertChooserFlags flags);
+
+G_END_DECLS
+
+#endif /* NMA_CERT_FILE_CHOOSER_H */


[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]