/*
* Copyright © 2012 Igalia S.L.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2, or (at your option)
* any later version.
*
* This program 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 General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*
*/
#include "config.h"
#include "ephy-certificate-dialog.h"
#define GCR_API_SUBJECT_TO_CHANGE
#include <gcr/gcr.h>
#include <glib/gi18n.h>
#include <libsoup/soup.h>
/**
* SECTION:ephy-certificate-dialog
* @short_description: A dialog to show SSL certificate information
*
* #EphyCertificateDialog shows information about SSL certificates.
*/
enum
{
PROP_0,
PROP_ADDRESS,
PROP_CERTIFICATE,
PROP_TLS_ERRORS
};
struct _EphyCertificateDialogPrivate
{
GtkWidget *icon;
GtkWidget *title;
GtkWidget *text;
};
G_DEFINE_TYPE (EphyCertificateDialog, ephy_certificate_dialog, GTK_TYPE_DIALOG)
static void
ephy_certificate_dialog_set_address (EphyCertificateDialog *dialog,
const char *address)
{
SoupURI *uri;
uri = soup_uri_new (address);
gtk_window_set_title (GTK_WINDOW (dialog), uri->host);
soup_uri_free (uri);
}
static void
ephy_certificate_dialog_set_certificate (EphyCertificateDialog *dialog,
GTlsCertificate *certificate)
{
GcrCertificate *simple_certificate;
GByteArray *certificate_data;
GtkWidget *certificate_widget;
GtkWidget *content_area;
g_object_get (certificate, "certificate", &certificate_data, NULL);
simple_certificate = gcr_simple_certificate_new ((const guchar *)certificate_data->data,
certificate_data->len);
g_byte_array_unref (certificate_data);
certificate_widget = GTK_WIDGET (gcr_certificate_widget_new (simple_certificate));
g_object_unref (simple_certificate);
content_area = gtk_dialog_get_content_area (GTK_DIALOG (dialog));
gtk_box_pack_start (GTK_BOX (content_area), certificate_widget, TRUE, TRUE, 0);
gtk_widget_show (certificate_widget);
}
static char *
get_error_messages_from_tls_errors (GTlsCertificateFlags tls_errors)
{
GPtrArray *errors = g_ptr_array_new ();
char *retval;
if (tls_errors & G_TLS_CERTIFICATE_BAD_IDENTITY)
g_ptr_array_add (errors, _("The certificate does not match the expected identity"));
if (tls_errors & G_TLS_CERTIFICATE_EXPIRED)
g_ptr_array_add (errors, _("The certificate has expired"));
if (tls_errors & G_TLS_CERTIFICATE_UNKNOWN_CA)
g_ptr_array_add (errors, _("The signing certificate authority is not known"));
if (tls_errors & G_TLS_CERTIFICATE_GENERIC_ERROR)
g_ptr_array_add (errors, _("The certificate contains errors"));
if (tls_errors & G_TLS_CERTIFICATE_REVOKED)
g_ptr_array_add (errors, _("The certificate has been revoked"));
if (tls_errors & G_TLS_CERTIFICATE_INSECURE)
g_ptr_array_add (errors, _("The certificate is signed using a weak signature algorithm"));
if (tls_errors & G_TLS_CERTIFICATE_NOT_ACTIVATED)
g_ptr_array_add (errors, _("The certificate activation time is still in the future"));
if (errors->len == 1)
retval = g_strdup (g_ptr_array_index (errors, 0));
else {
GString *message = g_string_new (NULL);
guint i;
for (i = 0; i < errors->len; i++) {
g_string_append_printf (message, "• %s",
(char *)g_ptr_array_index (errors, i));
if (i < errors->len - 1)
g_string_append_c (message, '\n');
}
retval = g_string_free (message, FALSE);
}
g_ptr_array_free (errors, TRUE);
return retval;
}
static void
ephy_certificate_dialog_set_tls_errors (EphyCertificateDialog *dialog,
GTlsCertificateFlags tls_errors)
{
EphyCertificateDialogPrivate *priv = dialog->priv;
GIcon *icon;
char *markup;
icon = tls_errors == 0 ?
g_themed_icon_new_with_default_fallbacks ("channel-secure-symbolic") :
g_themed_icon_new_with_default_fallbacks ("channel-insecure-symbolic");
gtk_image_set_from_gicon (GTK_IMAGE (priv->icon), icon, GTK_ICON_SIZE_DIALOG);
g_object_unref (icon);
markup = g_strdup_printf ("<span weight=\"bold\" size=\"large\">%s</span>",
tls_errors == 0 ?
_("The identity of this website has been verified") :
_("The identity of this website has not been verified"));
gtk_label_set_markup (GTK_LABEL (priv->title), markup);
g_free (markup);
if (tls_errors) {
char *text = get_error_messages_from_tls_errors (tls_errors);
gtk_label_set_text (GTK_LABEL (priv->text), text);
g_free (text);
gtk_widget_show (priv->text);
}
}
static void
ephy_certificate_dialog_set_property (GObject *object,
guint prop_id,
const GValue *value,
GParamSpec *pspec)
{
EphyCertificateDialog *dialog = EPHY_CERTIFICATE_DIALOG (object);
switch (prop_id) {
case PROP_ADDRESS:
ephy_certificate_dialog_set_address (dialog, g_value_get_string (value));
break;
case PROP_CERTIFICATE:
ephy_certificate_dialog_set_certificate (dialog, g_value_get_object (value));
break;
case PROP_TLS_ERRORS:
ephy_certificate_dialog_set_tls_errors (dialog, g_value_get_flags (value));
break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
}
}
static void
ephy_certificate_dialog_class_init (EphyCertificateDialogClass *klass)
{
GObjectClass *object_class = G_OBJECT_CLASS (klass);
object_class->set_property = ephy_certificate_dialog_set_property;
/**
* EphyCertificateDialog:address:
*
* The address of the website.
*/
g_object_class_install_property (object_class,
PROP_ADDRESS,
g_param_spec_string ("address",
"Address",
"The address of the website",
NULL,
G_PARAM_WRITABLE |
G_PARAM_CONSTRUCT_ONLY |
G_PARAM_STATIC_NAME |
G_PARAM_STATIC_NICK |
G_PARAM_STATIC_BLURB));
/**
* EphyCertificateDialog:certificate:
*
* The certificate of the website.
*/
g_object_class_install_property (object_class,
PROP_CERTIFICATE,
g_param_spec_object ("certificate",
"Certificate",
"The certificate of the website",
G_TYPE_TLS_CERTIFICATE,
G_PARAM_WRITABLE |
G_PARAM_CONSTRUCT_ONLY |
G_PARAM_STATIC_NAME |
G_PARAM_STATIC_NICK |
G_PARAM_STATIC_BLURB));
/**
* EphyCertificateDialog:tls-errors:
*
* The verification errors on the TLS certificate.
*/
g_object_class_install_property (object_class,
PROP_TLS_ERRORS,
g_param_spec_flags ("tls-errors",
"TLS Errors",
"The verification errors on the TLS certificate",
G_TYPE_TLS_CERTIFICATE_FLAGS,
0,
G_PARAM_WRITABLE |
G_PARAM_CONSTRUCT_ONLY |
G_PARAM_STATIC_NAME |
G_PARAM_STATIC_NICK |
G_PARAM_STATIC_BLURB));
g_type_class_add_private (object_class, sizeof (EphyCertificateDialogPrivate));
}
static void
ephy_certificate_dialog_init (EphyCertificateDialog *dialog)
{
GtkWidget *vbox, *hbox;
GtkWidget *content_area, *action_area;
EphyCertificateDialogPrivate *priv;
dialog->priv = G_TYPE_INSTANCE_GET_PRIVATE (dialog,
EPHY_TYPE_CERTIFICATE_DIALOG,
EphyCertificateDialogPrivate);
priv = dialog->priv;
gtk_container_set_border_width (GTK_CONTAINER (dialog), 5);
gtk_window_set_skip_taskbar_hint (GTK_WINDOW (dialog), TRUE);
hbox = gtk_box_new (GTK_ORIENTATION_HORIZONTAL, 12);
gtk_container_set_border_width (GTK_CONTAINER (hbox), 5);
priv->icon = gtk_image_new ();
gtk_widget_set_halign (priv->icon, GTK_ALIGN_CENTER);
gtk_widget_set_valign (priv->icon, GTK_ALIGN_START);
gtk_box_pack_start (GTK_BOX (hbox), priv->icon, FALSE, FALSE, 0);
gtk_widget_show (priv->icon);
vbox = gtk_box_new (GTK_ORIENTATION_VERTICAL, 12);
priv->title = gtk_label_new (NULL);
gtk_label_set_use_markup (GTK_LABEL (priv->title), TRUE);
gtk_label_set_line_wrap (GTK_LABEL (priv->title), TRUE);
gtk_label_set_selectable (GTK_LABEL (priv->title), TRUE);
gtk_widget_set_halign (priv->title, GTK_ALIGN_START);
gtk_widget_set_valign (priv->title, GTK_ALIGN_START);
gtk_misc_set_alignment (GTK_MISC (priv->title), 0.0, 0.0);
gtk_box_pack_start (GTK_BOX (vbox), priv->title, FALSE, FALSE, 0);
gtk_widget_show (priv->title);
priv->text = gtk_label_new (NULL);
gtk_label_set_line_wrap (GTK_LABEL (priv->text), TRUE);
gtk_label_set_selectable (GTK_LABEL (priv->text), TRUE);
gtk_widget_set_halign (priv->text, GTK_ALIGN_START);
gtk_widget_set_valign (priv->text, GTK_ALIGN_START);
gtk_misc_set_alignment (GTK_MISC (priv->text), 0.0, 0.0);
gtk_box_pack_start (GTK_BOX (vbox), priv->text, TRUE, TRUE, 0);
gtk_box_pack_start (GTK_BOX (hbox), vbox, TRUE, TRUE, 0);
gtk_widget_show (vbox);
content_area = gtk_dialog_get_content_area (GTK_DIALOG (dialog));
gtk_box_set_spacing (GTK_BOX (content_area), 14);
gtk_box_pack_start (GTK_BOX (content_area), hbox, FALSE, FALSE, 0);
gtk_widget_show (hbox);
action_area = gtk_dialog_get_action_area (GTK_DIALOG (dialog));
gtk_container_set_border_width (GTK_CONTAINER (action_area), 5);
gtk_box_set_spacing (GTK_BOX (action_area), 6);
}
GtkWidget *
ephy_certificate_dialog_new (GtkWindow *parent,
const char *address,
GTlsCertificate *certificate,
GTlsCertificateFlags tls_errors)
{
GtkWidget *dialog;
g_return_val_if_fail (address != NULL, NULL);
g_return_val_if_fail (G_IS_TLS_CERTIFICATE (certificate), NULL);
dialog = GTK_WIDGET (g_object_new (EPHY_TYPE_CERTIFICATE_DIALOG,
"address", address,
"certificate", certificate,
"tls-errors", tls_errors,
NULL));
gtk_dialog_add_buttons (GTK_DIALOG (dialog),
GTK_STOCK_CLOSE, GTK_RESPONSE_CLOSE,
NULL);
if (parent)
gtk_window_set_transient_for (GTK_WINDOW (dialog), parent);
return dialog;
}