[epiphany/tls-errors] TLS error page: add button to launch cert viewer



commit 881ef33f36cae7383bcc0cde9a6cc33302b676d1
Author: Michael Catanzaro <mcatanzaro igalia com>
Date:   Wed Jul 9 12:26:21 2014 -0500

    TLS error page: add button to launch cert viewer
    
    If the user experiences a TLS error, he needs some way to override it.
    We can either give the user a button that allows him to click straight
    through to the website, like Chromium does, or send him to a new dialog
    designed to explain the implications of adding a security exception,
    like Firefox does. Firefox's approach seems safest. (There are
    additional possibilites, such as requiring the user to install the
    certificate, which we can explore in the future, but for now let's
    handle this in a more traditional manner.)
    
    For now, use this button just to launch the existing certificate viewer.
    This is useless though, since it contains too much confusing technical
    information and does not actually allow you to add a security exception,
    so the next step will be to either to use a custom version of the cert
    viewer designed for this purpose, or to switch to a custom dialog
    instead.

 embed/ephy-embed-shell.c                 |   46 +++++++++++++++
 embed/ephy-web-view.c                    |   35 +++++++++++-
 embed/ephy-web-view.h                    |    3 +
 embed/web-extension/ephy-web-extension.c |   94 +++++++++++++++++++++++++++--
 src/ephy-window.c                        |   55 +++++++++++++++---
 src/resources/tls-error.html             |    9 +++
 6 files changed, 226 insertions(+), 16 deletions(-)
---
diff --git a/embed/ephy-embed-shell.c b/embed/ephy-embed-shell.c
index 1122eaf..01d6832 100644
--- a/embed/ephy-embed-shell.c
+++ b/embed/ephy-embed-shell.c
@@ -62,6 +62,7 @@ struct _EphyEmbedShellPrivate
   guint web_extensions_page_created_signal_id;
   guint web_extensions_form_auth_save_signal_id;
   guint web_extensions_remove_from_overview_signal_id;
+  guint web_extensions_open_certificate_viewer_signal_id;
 };
 
 enum
@@ -70,6 +71,7 @@ enum
   RESTORED_WINDOW,
   WEB_VIEW_CREATED,
   PAGE_CREATED,
+  OPEN_CERTIFICATE_VIEWER_REQUEST,
 
   LAST_SIGNAL
 };
@@ -267,6 +269,18 @@ web_extension_remove_from_overview (GDBusConnection *connection,
 }
 
 static void
+web_extension_open_certificate_viewer (GDBusConnection *connection,
+                                       const char *sender_name,
+                                       const char *object_path,
+                                       const char *interface_name,
+                                       const char *signal_name,
+                                       GVariant *parameters,
+                                       EphyEmbedShell *shell)
+{
+  g_signal_emit (shell, signals[OPEN_CERTIFICATE_VIEWER_REQUEST], 0);
+}
+
+static void
 web_extension_destroyed (EphyEmbedShell *shell,
                          GObject *web_extension)
 {
@@ -540,6 +554,17 @@ ephy_embed_shell_setup_web_extensions_connection (EphyEmbedShell *shell)
                                         (GDBusSignalCallback)web_extension_remove_from_overview,
                                         shell,
                                         NULL);
+  shell->priv->web_extensions_open_certificate_viewer_signal_id =
+    g_dbus_connection_signal_subscribe (shell->priv->bus,
+                                        NULL,
+                                        EPHY_WEB_EXTENSION_INTERFACE,
+                                        "OpenCertificateViewer",
+                                        EPHY_WEB_EXTENSION_OBJECT_PATH,
+                                        NULL,
+                                        G_DBUS_SIGNAL_FLAGS_NONE,
+                                        (GDBusSignalCallback)web_extension_open_certificate_viewer,
+                                        shell,
+                                        NULL);
 }
 
 static void
@@ -641,6 +666,11 @@ ephy_embed_shell_shutdown (GApplication* application)
     priv->web_extensions_remove_from_overview_signal_id = 0;
   }
 
+  if (priv->web_extensions_open_certificate_viewer_signal_id > 0) {
+    g_dbus_connection_signal_unsubscribe (priv->bus, priv->web_extensions_open_certificate_viewer_signal_id);
+    priv->web_extensions_open_certificate_viewer_signal_id = 0;
+  }
+
   g_list_foreach (priv->web_extensions, (GFunc)ephy_embed_shell_unwatch_web_extension, application);
 
   g_object_unref (ephy_embed_prefs_get_web_view_group ());
@@ -787,6 +817,22 @@ ephy_embed_shell_class_init (EphyEmbedShellClass *klass)
                   G_TYPE_UINT64,
                   EPHY_TYPE_WEB_EXTENSION_PROXY);
 
+  /**
+   * EphyEmbedShell::open-certificate-viewer-request:
+   * @shell: the #EphyEmbedShell
+   *
+   * The ::open-certificate-viewer-request signal is emitted when
+   * the web extension requests the certificate viewer be displayed
+   * for the current page. It is intended for use by #EphyWindow.
+   */
+  signals[OPEN_CERTIFICATE_VIEWER_REQUEST] =
+    g_signal_new ("open-certificate-viewer-request",
+                  EPHY_TYPE_EMBED_SHELL,
+                  G_SIGNAL_RUN_FIRST,
+                  0, NULL, NULL,
+                  g_cclosure_marshal_VOID__VOID,
+                  G_TYPE_NONE, 0);
+
   g_type_class_add_private (object_class, sizeof (EphyEmbedShellPrivate));
 }
 
diff --git a/embed/ephy-web-view.c b/embed/ephy-web-view.c
index fe66ce9..e153505 100644
--- a/embed/ephy-web-view.c
+++ b/embed/ephy-web-view.c
@@ -107,6 +107,7 @@ struct _EphyWebViewPrivate {
   /* TLS information. */
   GTlsCertificate *certificate;
   GTlsCertificateFlags tls_errors;
+  WebKitCertificateInfo *last_tls_error_info;
 
   /* Web Extension */
   EphyWebExtensionProxy *web_extension;
@@ -1885,6 +1886,11 @@ tls_error_cb (WebKitWebView *web_view,
   char *stylesheet;
   GBytes *html_file;
 
+  /* Save this or we'll lose it, since pressing the button triggers a new load. */
+  if (priv->last_tls_error_info != NULL)
+    webkit_certificate_info_free (priv->last_tls_error_info);
+  priv->last_tls_error_info = webkit_certificate_info_copy (info);
+
   priv->load_failed = TRUE;
   ephy_web_view_set_link_message (view, NULL);
   update_navigation_flags (view);
@@ -1918,7 +1924,9 @@ tls_error_cb (WebKitWebView *web_view,
                    page_title, stylesheet,
                    /* Title of error page when a website's TLS certificate is invalid */
                    _("Look out!"),
-                   msg);
+                   msg,
+                   /* Button on error page when a website's TLS certificate is invalid */
+                   _("Create Security Exception…"));
 
   g_bytes_unref (html_file);
   g_free (msg);
@@ -2884,3 +2892,28 @@ ephy_web_view_set_visit_type (EphyWebView *view, EphyHistoryPageVisitType visit_
 
   view->priv->visit_type = visit_type;
 }
+
+/**
+ * ephy_web_view_get_last_tls_error_info:
+ * @view: an #EphyWebView
+ * @certificate: (out) (transfer none): return value of TLS certificate, or NULL
+ * @errors: (out): return value of TLS errors
+ **/
+void
+ephy_web_view_get_last_tls_error_info (EphyWebView *view,
+                                       GTlsCertificate **certificate,
+                                       GTlsCertificateFlags *errors)
+{
+  WebKitCertificateInfo *info = view->priv->last_tls_error_info;
+
+  g_return_if_fail (EPHY_IS_WEB_VIEW (view));
+
+  if (info == NULL) {
+    *certificate = NULL;
+    *errors = 0;
+    return;
+  }
+
+  *certificate = webkit_certificate_info_get_tls_certificate (info);
+  *errors = webkit_certificate_info_get_tls_errors (info);
+}
diff --git a/embed/ephy-web-view.h b/embed/ephy-web-view.h
index 78f9a15..7551e99 100644
--- a/embed/ephy-web-view.h
+++ b/embed/ephy-web-view.h
@@ -174,6 +174,9 @@ void                       ephy_web_view_get_web_app_title        (EphyWebView
 char                      *ephy_web_view_get_web_app_title_finish (EphyWebView               *view,
                                                                    GAsyncResult              *result,
                                                                    GError                   **error);
+void                       ephy_web_view_get_last_tls_error_info  (EphyWebView               *view,
+                                                                   GTlsCertificate          **certificate,
+                                                                   GTlsCertificateFlags      *errors);
 
 G_END_DECLS
 
diff --git a/embed/web-extension/ephy-web-extension.c b/embed/web-extension/ephy-web-extension.c
index 75cda3c..9ae6a7d 100644
--- a/embed/web-extension/ephy-web-extension.c
+++ b/embed/web-extension/ephy-web-extension.c
@@ -107,6 +107,7 @@ static const char introspection_xml[] =
   "   <arg type='s' name='host' direction='in'/>"
   "  </method>"
   "  <method name='HistoryClear'/>"
+  "  <signal name='OpenCertificateViewer'/>"
   " </interface>"
   "</node>";
 
@@ -1245,17 +1246,81 @@ static const GDBusInterfaceVTable interface_vtable = {
   NULL
 };
 
+static JSValueRef
+open_certificate_viewer_cb (JSContextRef context,
+                            JSObjectRef function,
+                            JSObjectRef this_object,
+                            size_t argument_count,
+                            const JSValueRef arguments[],
+                            JSValueRef *exception)
+{
+  EphyWebExtension *extension;
+  GError *error = NULL;
+
+  extension = EPHY_WEB_EXTENSION (JSObjectGetPrivate (this_object));
+
+  if (!extension->priv->dbus_connection)
+    return;
+
+  g_dbus_connection_emit_signal (extension->priv->dbus_connection,
+                                 NULL,
+                                 EPHY_WEB_EXTENSION_OBJECT_PATH,
+                                 EPHY_WEB_EXTENSION_INTERFACE,
+                                 "OpenCertificateViewer",
+                                 NULL,
+                                 &error);
+
+  if (error) {
+    g_warning ("Error emitting signal OpenCertificateViewer: %s\n", error->message);
+    g_error_free (error);
+  }
+
+  return JSValueMakeUndefined (context);
+}
+
+static const JSStaticFunction certificate_viewer_static_funcs[] =
+{
+  { "open", open_certificate_viewer_cb, kJSPropertyAttributeReadOnly | kJSPropertyAttributeDontDelete },
+  { NULL, NULL, 0 }
+};
+
 static void
-window_object_cleared_cb (WebKitScriptWorld *world,
-                          WebKitWebPage     *web_page,
-                          WebKitFrame       *frame,
-                          EphyWebExtension  *extension)
+prepare_certificate_viewer_js (WebKitScriptWorld *world,
+                               WebKitWebPage *web_page,
+                               WebKitFrame *frame,
+                               EphyWebExtension *extension)
 {
   JSGlobalContextRef context;
-  EphyWebOverview *overview;
+  JSObjectRef global_object;
+  JSClassDefinition class_def;
+  JSClassRef class;
+  JSObjectRef class_object;
+  JSStringRef str;
 
-  if (g_strcmp0 (webkit_web_page_get_uri (web_page), "ephy-about:overview") != 0)
-    return;
+  context = webkit_frame_get_javascript_context_for_script_world (frame, world);
+  global_object = JSContextGetGlobalObject (context);
+
+  class_def = kJSClassDefinitionEmpty;
+  class_def.className = "CertificateViewer";
+  class_def.staticFunctions = certificate_viewer_static_funcs;
+
+  class = JSClassCreate (&class_def);
+  class_object = JSObjectMake (context, class, extension);
+  str = JSStringCreateWithUTF8CString ("CertificateViewer");
+  JSObjectSetProperty (context, global_object, str, class_object, kJSPropertyAttributeNone, NULL);
+
+  JSClassRelease (class);
+  JSStringRelease (str);
+}
+
+static void
+prepare_overview (WebKitScriptWorld *world,
+                  WebKitWebPage *web_page,
+                  WebKitFrame *frame,
+                  EphyWebExtension *extension)
+{
+  EphyWebOverview *overview;
+  JSGlobalContextRef context;
 
   overview = ephy_web_overview_new (web_page, extension->priv->overview_model);
   g_signal_connect (overview, "item-removed",
@@ -1266,6 +1331,21 @@ window_object_cleared_cb (WebKitScriptWorld *world,
 }
 
 static void
+window_object_cleared_cb (WebKitScriptWorld *world,
+                          WebKitWebPage     *web_page,
+                          WebKitFrame       *frame,
+                          EphyWebExtension  *extension)
+{
+  if (g_strcmp0 (webkit_web_page_get_uri (web_page), "ephy-about:overview") == 0) {
+    prepare_overview (world, web_page, frame, extension);
+    return;
+  }
+
+  // FIXME ideally would not be available to all pages...
+  prepare_certificate_viewer_js (world, web_page, frame, extension);
+}
+
+static void
 ephy_web_extension_dispose (GObject *object)
 {
   EphyWebExtension *extension = EPHY_WEB_EXTENSION (object);
diff --git a/src/ephy-window.c b/src/ephy-window.c
index 4c48ace..b45ab0f 100644
--- a/src/ephy-window.c
+++ b/src/ephy-window.c
@@ -3095,20 +3095,17 @@ zoom_to_level_cb (GtkAction *action,
 }
 
 static void
-lock_clicked_cb (EphyLocationController *controller,
-                EphyWindow *window)
+open_certificate_viewer (EphyWindow *window,
+                         GTlsCertificate *certificate,
+                         GTlsCertificateFlags tls_errors)
 {
        EphyWindowPrivate *priv = window->priv;
-       EphyWebView *view;
-       GTlsCertificate *certificate;
-       GTlsCertificateFlags tls_errors;
        GtkWidget *certificate_dialog;
 
-       view = ephy_embed_get_web_view (priv->active_embed);
-       ephy_web_view_get_security_level (view, NULL, &certificate, &tls_errors);
+       g_return_if_fail (G_IS_TLS_CERTIFICATE (certificate));
 
        certificate_dialog = ephy_certificate_dialog_new (GTK_WINDOW (window),
-                                                         ephy_location_controller_get_address (controller),
+                                                         ephy_location_controller_get_address 
(priv->location_controller),
                                                          certificate,
                                                          tls_errors);
        gtk_window_set_destroy_with_parent (GTK_WINDOW (certificate_dialog), TRUE);
@@ -3118,6 +3115,43 @@ lock_clicked_cb (EphyLocationController *controller,
        gtk_widget_show (certificate_dialog);
 }
 
+static void
+open_certificate_viewer_request_cb (EphyEmbedShell *embed_shell,
+                                   gpointer user_data)
+{
+       EphyWindow *window = EPHY_WINDOW (user_data);
+       EphyWindowPrivate *priv = window->priv;
+       EphyWebView *view;
+       GTlsCertificate *certificate;
+       GTlsCertificateFlags tls_errors;
+
+       /* We're on the TLS error page */
+       view = ephy_embed_get_web_view (priv->active_embed);
+       ephy_web_view_get_last_tls_error_info (view, &certificate, &tls_errors);
+
+       open_certificate_viewer (window, certificate, tls_errors);
+}
+
+static void
+lock_clicked_cb (EphyLocationController *controller,
+                EphyWindow *window)
+{
+       EphyWindowPrivate *priv = window->priv;
+       EphyWebView *view;
+       GTlsCertificate *certificate;
+       GTlsCertificateFlags tls_errors;
+
+       view = ephy_embed_get_web_view (priv->active_embed);
+       ephy_web_view_get_security_level (view, NULL, &certificate, &tls_errors);
+
+       g_return_if_fail (certificate);
+       g_return_if_fail (G_IS_TLS_CERTIFICATE (certificate));
+
+       open_certificate_viewer (window,
+                                certificate,
+                                tls_errors);
+}
+
 static GtkWidget *
 setup_toolbar (EphyWindow *window)
 {
@@ -3418,6 +3452,11 @@ ephy_window_constructor (GType type,
 
        ephy_window_set_chrome (window, chrome);
 
+        g_signal_connect (ephy_embed_shell_get_default (),
+                         "open-certificate-viewer-request",
+                         G_CALLBACK (open_certificate_viewer_request_cb),
+                         object);
+
        return object;
 }
 
diff --git a/src/resources/tls-error.html b/src/resources/tls-error.html
index 1b42f5e..c91c5e0 100644
--- a/src/resources/tls-error.html
+++ b/src/resources/tls-error.html
@@ -22,6 +22,12 @@
   <title>%s</title>
   <style type="text/css">%s</style>
   </style>
+  <script type="text/javascript">
+    function open_certificate_viewer()
+    {
+      CertificateViewer.open();
+    }
+  </script>
 </head>
 <body>
   <div id="container">
@@ -30,6 +36,9 @@
           <div class="explanation">
             %s
           </div>
+          <div class="buttonbox">
+            <button onclick="javascript:open_certificate_viewer()">%s</button>
+          </div>
       </div>
   </div>
 </body>


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