2 * empathy-tls-dialog.c - Source for EmpathyTLSDialog
3 * Copyright (C) 2010 Collabora Ltd.
4 * @author Cosimo Cecchi <cosimo.cecchi@collabora.co.uk>
6 * This library 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.
11 * This library 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.
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 St, Fifth Floor, Boston, MA 02110-1301 USA
22 #include "empathy-tls-dialog.h"
24 #include <glib/gi18n-lib.h>
27 #include "empathy-utils.h"
29 #define DEBUG_FLAG EMPATHY_DEBUG_TLS
30 #include "empathy-debug.h"
32 G_DEFINE_TYPE (EmpathyTLSDialog
, empathy_tls_dialog
,
33 GTK_TYPE_MESSAGE_DIALOG
)
35 #define GET_PRIV(obj) EMPATHY_GET_PRIV (obj, EmpathyTLSDialog);
38 PROP_TLS_CERTIFICATE
= 1,
47 TpTLSCertificate
*certificate
;
48 TpTLSCertificateRejectReason reason
;
54 } EmpathyTLSDialogPriv
;
57 empathy_tls_dialog_get_property (GObject
*object
,
62 EmpathyTLSDialogPriv
*priv
= GET_PRIV (object
);
66 case PROP_TLS_CERTIFICATE
:
67 g_value_set_object (value
, priv
->certificate
);
70 g_value_set_uint (value
, priv
->reason
);
73 g_value_set_boolean (value
, priv
->remember
);
76 g_value_set_boxed (value
, priv
->details
);
79 G_OBJECT_WARN_INVALID_PROPERTY_ID (object
, property_id
, pspec
);
85 empathy_tls_dialog_set_property (GObject
*object
,
90 EmpathyTLSDialogPriv
*priv
= GET_PRIV (object
);
94 case PROP_TLS_CERTIFICATE
:
95 priv
->certificate
= g_value_dup_object (value
);
98 priv
->reason
= g_value_get_uint (value
);
101 priv
->details
= g_value_dup_boxed (value
);
104 G_OBJECT_WARN_INVALID_PROPERTY_ID (object
, property_id
, pspec
);
110 empathy_tls_dialog_dispose (GObject
*object
)
112 EmpathyTLSDialogPriv
*priv
= GET_PRIV (object
);
114 if (priv
->dispose_run
)
117 priv
->dispose_run
= TRUE
;
119 tp_clear_object (&priv
->certificate
);
121 G_OBJECT_CLASS (empathy_tls_dialog_parent_class
)->dispose (object
);
125 empathy_tls_dialog_finalize (GObject
*object
)
127 EmpathyTLSDialogPriv
*priv
= GET_PRIV (object
);
129 tp_clear_boxed (G_TYPE_HASH_TABLE
, &priv
->details
);
131 G_OBJECT_CLASS (empathy_tls_dialog_parent_class
)->finalize (object
);
135 reason_to_string (EmpathyTLSDialog
*self
)
138 const gchar
*reason_str
;
139 TpTLSCertificateRejectReason reason
;
141 EmpathyTLSDialogPriv
*priv
= GET_PRIV (self
);
143 str
= g_string_new (NULL
);
144 reason
= priv
->reason
;
145 details
= priv
->details
;
147 g_string_append (str
, _("The identity provided by the chat server cannot be "
149 g_string_append (str
, "\n\n");
153 case TP_TLS_CERTIFICATE_REJECT_REASON_UNTRUSTED
:
154 reason_str
= _("The certificate is not signed by a Certification "
157 case TP_TLS_CERTIFICATE_REJECT_REASON_EXPIRED
:
158 reason_str
= _("The certificate has expired.");
160 case TP_TLS_CERTIFICATE_REJECT_REASON_NOT_ACTIVATED
:
161 reason_str
= _("The certificate hasn’t yet been activated.");
163 case TP_TLS_CERTIFICATE_REJECT_REASON_FINGERPRINT_MISMATCH
:
164 reason_str
= _("The certificate does not have the expected fingerprint.");
166 case TP_TLS_CERTIFICATE_REJECT_REASON_HOSTNAME_MISMATCH
:
167 reason_str
= _("The hostname verified by the certificate doesn’t match "
170 case TP_TLS_CERTIFICATE_REJECT_REASON_SELF_SIGNED
:
171 reason_str
= _("The certificate is self-signed.");
173 case TP_TLS_CERTIFICATE_REJECT_REASON_REVOKED
:
174 reason_str
= _("The certificate has been revoked by the issuing "
175 "Certification Authority.");
177 case TP_TLS_CERTIFICATE_REJECT_REASON_INSECURE
:
178 reason_str
= _("The certificate is cryptographically weak.");
180 case TP_TLS_CERTIFICATE_REJECT_REASON_LIMIT_EXCEEDED
:
181 reason_str
= _("The certificate length exceeds verifiable limits.");
183 case TP_TLS_CERTIFICATE_REJECT_REASON_UNKNOWN
:
185 reason_str
= _("The certificate is malformed.");
189 g_string_append (str
, reason_str
);
191 /* add more information in case of HOSTNAME_MISMATCH */
192 if (reason
== TP_TLS_CERTIFICATE_REJECT_REASON_HOSTNAME_MISMATCH
)
194 const gchar
*expected_hostname
, *certificate_hostname
;
196 expected_hostname
= tp_asv_get_string (details
, "expected-hostname");
197 certificate_hostname
= tp_asv_get_string (details
,
198 "certificate-hostname");
200 if (expected_hostname
!= NULL
&& certificate_hostname
!= NULL
)
202 g_string_append (str
, "\n\n");
203 g_string_append_printf (str
, _("Expected hostname: %s"),
205 g_string_append (str
, "\n");
206 g_string_append_printf (str
, _("Certificate hostname: %s"),
207 certificate_hostname
);
211 return g_string_free (str
, FALSE
);
215 build_gcr_widget (EmpathyTLSDialog
*self
)
217 GcrCertificateWidget
*widget
;
218 GcrCertificate
*certificate
;
219 GPtrArray
*cert_chain
= NULL
;
222 EmpathyTLSDialogPriv
*priv
= GET_PRIV (self
);
224 g_object_get (priv
->certificate
,
225 "cert-data", &cert_chain
,
227 first_cert
= g_ptr_array_index (cert_chain
, 0);
229 certificate
= gcr_simple_certificate_new ((const guchar
*) first_cert
->data
,
231 widget
= gcr_certificate_widget_new (certificate
);
233 /* FIXME: make this widget bigger by default -- GTK+ should really handle
234 * this sort of thing for us */
235 gtk_widget_get_preferred_height (GTK_WIDGET (widget
), NULL
, &height
);
236 /* force the widget to at least 150 pixels high */
237 gtk_widget_set_size_request (GTK_WIDGET (widget
), -1, MAX (height
, 150));
239 g_object_unref (certificate
);
240 g_ptr_array_unref (cert_chain
);
242 return GTK_WIDGET (widget
);
246 checkbox_toggled_cb (GtkToggleButton
*checkbox
,
249 EmpathyTLSDialog
*self
= user_data
;
250 EmpathyTLSDialogPriv
*priv
= GET_PRIV (self
);
252 priv
->remember
= gtk_toggle_button_get_active (checkbox
);
253 g_object_notify (G_OBJECT (self
), "remember");
257 certificate_invalidated_cb (TpTLSCertificate
*certificate
,
261 EmpathyTLSDialog
*self
)
263 gtk_widget_destroy (GTK_WIDGET (self
));
267 empathy_tls_dialog_constructed (GObject
*object
)
269 GtkWidget
*content_area
, *expander
, *details
, *checkbox
;
271 EmpathyTLSDialog
*self
= EMPATHY_TLS_DIALOG (object
);
272 GtkMessageDialog
*message_dialog
= GTK_MESSAGE_DIALOG (self
);
273 GtkDialog
*dialog
= GTK_DIALOG (self
);
274 EmpathyTLSDialogPriv
*priv
= GET_PRIV (self
);
276 gtk_dialog_add_buttons (dialog
,
277 GTK_STOCK_CANCEL
, GTK_RESPONSE_CANCEL
,
278 _("C_ontinue"), GTK_RESPONSE_YES
,
281 text
= reason_to_string (self
);
283 g_object_set (message_dialog
,
284 "title", _("Untrusted connection"),
285 "text", _("This connection is untrusted. Would you like to "
287 "secondary-text", text
,
292 content_area
= gtk_dialog_get_content_area (dialog
);
294 checkbox
= gtk_check_button_new_with_label (
295 _("Remember this choice for future connections"));
296 gtk_box_pack_end (GTK_BOX (content_area
), checkbox
, FALSE
, FALSE
, 0);
297 gtk_widget_show (checkbox
);
298 g_signal_connect (checkbox
, "toggled", G_CALLBACK (checkbox_toggled_cb
),
301 text
= g_strdup_printf ("<b>%s</b>", _("Certificate Details"));
302 expander
= gtk_expander_new (text
);
303 gtk_expander_set_use_markup (GTK_EXPANDER (expander
), TRUE
);
304 gtk_box_pack_end (GTK_BOX (content_area
), expander
, TRUE
, TRUE
, 0);
305 gtk_widget_show (expander
);
309 details
= build_gcr_widget (self
);
310 gtk_container_add (GTK_CONTAINER (expander
), details
);
311 gtk_widget_show (details
);
313 gtk_window_set_keep_above (GTK_WINDOW (self
), TRUE
);
315 tp_g_signal_connect_object (priv
->certificate
, "invalidated",
316 G_CALLBACK (certificate_invalidated_cb
), self
, 0);
320 empathy_tls_dialog_init (EmpathyTLSDialog
*self
)
322 self
->priv
= G_TYPE_INSTANCE_GET_PRIVATE (self
,
323 EMPATHY_TYPE_TLS_DIALOG
, EmpathyTLSDialogPriv
);
327 empathy_tls_dialog_class_init (EmpathyTLSDialogClass
*klass
)
330 GObjectClass
*oclass
= G_OBJECT_CLASS (klass
);
332 g_type_class_add_private (klass
, sizeof (EmpathyTLSDialogPriv
));
334 oclass
->set_property
= empathy_tls_dialog_set_property
;
335 oclass
->get_property
= empathy_tls_dialog_get_property
;
336 oclass
->dispose
= empathy_tls_dialog_dispose
;
337 oclass
->finalize
= empathy_tls_dialog_finalize
;
338 oclass
->constructed
= empathy_tls_dialog_constructed
;
340 pspec
= g_param_spec_object ("certificate", "The TpTLSCertificate",
341 "The TpTLSCertificate to be displayed.",
342 TP_TYPE_TLS_CERTIFICATE
,
343 G_PARAM_CONSTRUCT_ONLY
| G_PARAM_READWRITE
| G_PARAM_STATIC_STRINGS
);
344 g_object_class_install_property (oclass
, PROP_TLS_CERTIFICATE
, pspec
);
346 pspec
= g_param_spec_uint ("reason", "The reason",
347 "The reason why the certificate is being asked for confirmation.",
348 0, TP_NUM_TLS_CERTIFICATE_REJECT_REASONS
- 1,
349 TP_TLS_CERTIFICATE_REJECT_REASON_UNKNOWN
,
350 G_PARAM_CONSTRUCT_ONLY
| G_PARAM_READWRITE
| G_PARAM_STATIC_STRINGS
);
351 g_object_class_install_property (oclass
, PROP_REASON
, pspec
);
353 pspec
= g_param_spec_boolean ("remember", "Whether to remember the decision",
354 "Whether we should remember the decision for this certificate.",
356 G_PARAM_READABLE
| G_PARAM_STATIC_STRINGS
);
357 g_object_class_install_property (oclass
, PROP_REMEMBER
, pspec
);
359 pspec
= g_param_spec_boxed ("details", "Rejection details",
360 "Additional details about the rejection of this certificate.",
362 G_PARAM_CONSTRUCT_ONLY
| G_PARAM_READWRITE
| G_PARAM_STATIC_STRINGS
);
363 g_object_class_install_property (oclass
, PROP_DETAILS
, pspec
);
367 empathy_tls_dialog_new (TpTLSCertificate
*certificate
,
368 TpTLSCertificateRejectReason reason
,
371 g_assert (TP_IS_TLS_CERTIFICATE (certificate
));
373 return g_object_new (EMPATHY_TYPE_TLS_DIALOG
,
374 "message-type", GTK_MESSAGE_WARNING
,
375 "certificate", certificate
,