[epiphany/pgriffis/web-extension/load-thread] WebExtensions: Add support for web_accessible_resources




commit c401144376f21b6c8c4ef28114eacf99d3a19d8e
Author: Patrick Griffis <pgriffis igalia com>
Date:   Sat Jun 25 18:43:04 2022 -0500

    WebExtensions: Add support for web_accessible_resources
    
    This filters requests not originating from the extension itself.
    
    Closes #1790

 src/webextension/ephy-web-extension-manager.c | 125 +++++++++++---------------
 src/webextension/ephy-web-extension.c         |  44 +++++++++
 src/webextension/ephy-web-extension.h         |   4 +
 3 files changed, 101 insertions(+), 72 deletions(-)
---
diff --git a/src/webextension/ephy-web-extension-manager.c b/src/webextension/ephy-web-extension-manager.c
index d01ec151c..ede69c9b1 100644
--- a/src/webextension/ephy-web-extension-manager.c
+++ b/src/webextension/ephy-web-extension-manager.c
@@ -120,6 +120,19 @@ ephy_web_extension_manager_remove_from_list (EphyWebExtensionManager *self,
   g_signal_emit (self, signals[CHANGED], 0);
 }
 
+static EphyWebExtension *
+ephy_web_extension_manager_get_extension_by_guid (EphyWebExtensionManager *self,
+                                                  const char              *guid)
+{
+  for (guint i = 0; i < self->web_extensions->len; i++) {
+    EphyWebExtension *web_extension = g_ptr_array_index (self->web_extensions, i);
+    if (strcmp (guid, ephy_web_extension_get_guid (web_extension)) == 0)
+      return web_extension;
+  }
+
+  return NULL;
+}
+
 static void
 on_web_extension_loaded (GObject      *source_object,
                          GAsyncResult *result,
@@ -189,49 +202,59 @@ ephy_web_extension_manager_scan_directory_async (EphyWebExtensionManager *self,
 }
 
 static void
-main_context_web_extension_scheme_cb (WebKitURISchemeRequest *request,
-                                      gpointer                user_data)
+destroy_widget_list (GSList *widget_list)
 {
-  EphyWebExtensionManager *self = EPHY_WEB_EXTENSION_MANAGER (user_data);
-  EphyWebExtension *web_extension = NULL;
-  const char *path;
+  g_slist_free_full (widget_list, (GDestroyNotify)gtk_widget_destroy);
+}
+
+static void
+ephy_webextension_scheme_cb (WebKitURISchemeRequest *request,
+                             gpointer                user_data)
+{
+  EphyWebExtensionManager *self = ephy_web_extension_manager_get_default ();
+  EphyWebExtension *web_extension = user_data;
+  EphyWebExtension *target_web_extension;
+  g_autoptr (GInputStream) stream = NULL;
+  g_autoptr (GUri) uri = NULL;
+  g_autoptr (GError) error = NULL;
   const unsigned char *data;
   gsize length;
-  g_autoptr (GInputStream) stream = NULL;
-  g_auto (GStrv) split = NULL;
-
-  path = webkit_uri_scheme_request_get_uri (request) + strlen ("ephy-webextension://");
 
-  split = g_strsplit (path, "/", -1);
-  for (guint i = 0; i < self->web_extensions->len; i++) {
-    EphyWebExtension *ext = g_ptr_array_index (self->web_extensions, i);
-
-    if (strcmp (ephy_web_extension_get_guid (ext), split[0]) == 0) {
-      web_extension = ext;
-      break;
-    }
+  uri = g_uri_parse (webkit_uri_scheme_request_get_uri (request),
+                     G_URI_FLAGS_ENCODED_PATH | G_URI_FLAGS_SCHEME_NORMALIZE,
+                     &error);
+  if (!uri) {
+    webkit_uri_scheme_request_finish_error (request, g_steal_pointer (&error));
+    return;
   }
 
-  if (!web_extension)
+  target_web_extension = ephy_web_extension_manager_get_extension_by_guid (self, g_uri_get_host (uri));
+  if (!target_web_extension) {
+    error = g_error_new (WEB_EXTENSION_ERROR, WEB_EXTENSION_ERROR_INVALID_HOST, "Could not find extension 
%s", g_uri_get_host (uri));
+    webkit_uri_scheme_request_finish_error (request, g_steal_pointer (&error));
     return;
+  }
 
-  /* FIXME: This needs to be filtered by the extension manifest's "web_accessible_resources"
-   * property which involves some pattern matching. */
+  /* If this is not originating from the same WebExtension view we must find it and filter it by 
web_accessible_resources. */
+  if (web_extension != target_web_extension) {
+    if (!ephy_web_extension_has_web_accessible_resource (target_web_extension, g_uri_get_path (uri) + 1)) {
+      error = g_error_new (G_IO_ERROR, G_IO_ERROR_PERMISSION_DENIED, "'%s' is not a 
web_accessible_resource", g_uri_get_path (uri));
+      webkit_uri_scheme_request_finish_error (request, g_steal_pointer (&error));
+      return;
+    }
+  }
 
-  data = ephy_web_extension_get_resource (web_extension, path + strlen (split[0]) + 1, &length);
-  if (!data)
+  data = ephy_web_extension_get_resource (target_web_extension, g_uri_get_path (uri) + 1, &length);
+  if (!data) {
+    error = g_error_new (G_IO_ERROR, G_IO_ERROR_NOT_FOUND, "'%s' was not found", g_uri_get_path (uri));
+    webkit_uri_scheme_request_finish_error (request, g_steal_pointer (&error));
     return;
+  }
 
   stream = g_memory_input_stream_new_from_data (data, length, NULL);
   webkit_uri_scheme_request_finish (request, stream, length, NULL);
 }
 
-static void
-destroy_widget_list (GSList *widget_list)
-{
-  g_slist_free_full (widget_list, (GDestroyNotify)gtk_widget_destroy);
-}
-
 static void
 ephy_web_extension_manager_constructed (GObject *object)
 {
@@ -286,7 +309,7 @@ ephy_web_extension_manager_init (EphyWebExtensionManager *self)
   WebKitWebContext *web_context;
 
   web_context = ephy_embed_shell_get_web_context (ephy_embed_shell_get_default ());
-  webkit_web_context_register_uri_scheme (web_context, "ephy-webextension", 
main_context_web_extension_scheme_cb, self, NULL);
+  webkit_web_context_register_uri_scheme (web_context, "ephy-webextension", ephy_webextension_scheme_cb, 
NULL, NULL);
   webkit_security_manager_register_uri_scheme_as_secure (webkit_web_context_get_security_manager 
(web_context),
                                                          "ephy-webextension");
 
@@ -798,35 +821,6 @@ page_attached_cb (HdyTabView *tab_view,
   ephy_web_extension_manager_update_location_entry (self, window);
 }
 
-static void
-web_extension_cb (WebKitURISchemeRequest *request,
-                  gpointer                user_data)
-{
-  EphyWebExtension *web_extension = EPHY_WEB_EXTENSION (user_data);
-  const char *path;
-  const unsigned char *data;
-  gsize length;
-  g_autoptr (GInputStream) stream = NULL;
-  g_autoptr (GError) error = NULL;
-
-  /* FIXME: For paths on different hosts we should support web_accessible_resources. */
-  path = webkit_uri_scheme_request_get_path (request);
-
-  /* FIXME: This may be the place to handle predefined messages and localized CSS:
-   * 
https://developer.mozilla.org/en-US/docs/Mozilla/Add-ons/WebExtensions/Internationalization#predefined_messages
-   */
-
-  data = ephy_web_extension_get_resource (web_extension, path + 1, &length);
-  if (!data) {
-    error = g_error_new (G_IO_ERROR, G_IO_ERROR_FAILED, "Resource not found: %s", path);
-    webkit_uri_scheme_request_finish_error (request, error);
-    return;
-  }
-
-  stream = g_memory_input_stream_new_from_data (data, length, NULL);
-  webkit_uri_scheme_request_finish (request, stream, length, NULL);
-}
-
 static void
 init_web_extension_api (WebKitWebContext *web_context,
                         EphyWebExtension *web_extension)
@@ -918,7 +912,7 @@ ephy_web_extensions_manager_create_web_extensions_webview (EphyWebExtension *web
 
   web_context = webkit_web_context_new ();
 
-  webkit_web_context_register_uri_scheme (web_context, "ephy-webextension", web_extension_cb, web_extension, 
NULL);
+  webkit_web_context_register_uri_scheme (web_context, "ephy-webextension", ephy_webextension_scheme_cb, 
web_extension, NULL);
   webkit_security_manager_register_uri_scheme_as_secure (webkit_web_context_get_security_manager 
(web_context),
                                                          "ephy-webextension");
   g_signal_connect_object (web_context, "initialize-web-extensions", G_CALLBACK (init_web_extension_api), 
web_extension, 0);
@@ -1332,19 +1326,6 @@ ephy_web_extension_manager_get_page_action (EphyWebExtensionManager *self,
   return ret;
 }
 
-static EphyWebExtension *
-ephy_web_extension_manager_get_extension_by_guid (EphyWebExtensionManager *self,
-                                                  const char              *guid)
-{
-  for (guint i = 0; i < self->web_extensions->len; i++) {
-    EphyWebExtension *web_extension = g_ptr_array_index (self->web_extensions, i);
-    if (strcmp (guid, ephy_web_extension_get_guid (web_extension)) == 0)
-      return web_extension;
-  }
-
-  return NULL;
-}
-
 void
 ephy_web_extension_manager_handle_notifications_action (EphyWebExtensionManager *self,
                                                         GVariant                *params)
diff --git a/src/webextension/ephy-web-extension.c b/src/webextension/ephy-web-extension.c
index 0b65f0cac..237943026 100644
--- a/src/webextension/ephy-web-extension.c
+++ b/src/webextension/ephy-web-extension.c
@@ -107,6 +107,7 @@ struct _EphyWebExtension {
   GCancellable *cancellable;
   char *local_storage_path;
   JsonNode *local_storage;
+  GHashTable *web_accessible_resources;
 };
 
 G_DEFINE_QUARK (web - extension - error - quark, web_extension_error)
@@ -752,6 +753,24 @@ web_extension_add_permission (JsonArray *array,
   g_hash_table_add (self->permissions, g_strdup (permission));
 }
 
+static void
+web_extension_add_web_accessible_resource (JsonArray *array,
+                                           guint      index_,
+                                           JsonNode  *element_node,
+                                           gpointer   user_data)
+{
+  EphyWebExtension *self = EPHY_WEB_EXTENSION (user_data);
+  const char *web_accessible_resource = json_node_get_string (element_node);
+
+  if (!web_accessible_resource)
+    return;
+
+  if (!self->web_accessible_resources)
+    self->web_accessible_resources = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, NULL);
+
+  g_hash_table_add (self->web_accessible_resources, g_strdup (web_accessible_resource));
+}
+
 static void
 ephy_web_extension_dispose (GObject *object)
 {
@@ -775,6 +794,7 @@ ephy_web_extension_dispose (GObject *object)
   g_clear_pointer (&self->permissions, g_hash_table_unref);
   g_clear_pointer (&self->host_permissions, g_ptr_array_unref);
   g_clear_pointer (&self->local_storage, json_node_unref);
+  g_clear_pointer (&self->web_accessible_resources, g_hash_table_unref);
 
   g_clear_pointer (&self->page_action, web_extension_page_action_free);
   g_clear_pointer (&self->browser_action, web_extension_browser_action_free);
@@ -911,6 +931,20 @@ ephy_web_extension_parse_manifest (EphyWebExtension  *self,
     json_array_foreach_element (array, web_extension_add_permission, self);
   }
 
+  if (json_object_has_member (root_object, "web_accessible_resources")) {
+    JsonNode *node;
+    JsonArray *array;
+
+    node = json_object_get_member (root_object, "web_accessible_resources");
+    if (!JSON_NODE_HOLDS_ARRAY (node)) {
+      g_set_error (error, WEB_EXTENSION_ERROR, WEB_EXTENSION_ERROR_INVALID_MANIFEST, 
"web_accessible_resources is not an array");
+      return FALSE;
+    }
+
+    array = json_node_get_array (node);
+    json_array_foreach_element (array, web_extension_add_web_accessible_resource, self);
+  }
+
   return TRUE;
 }
 
@@ -1576,3 +1610,13 @@ ephy_web_extension_create_sender_object (EphyWebExtension *self,
 
   return json_to_string (node, FALSE);
 }
+
+gboolean
+ephy_web_extension_has_web_accessible_resource (EphyWebExtension *self,
+                                                const char       *path)
+{
+  if (!self->web_accessible_resources)
+    return FALSE;
+
+  return g_hash_table_contains (self->web_accessible_resources, path);
+}
diff --git a/src/webextension/ephy-web-extension.h b/src/webextension/ephy-web-extension.h
index 008217c90..a0601e804 100644
--- a/src/webextension/ephy-web-extension.h
+++ b/src/webextension/ephy-web-extension.h
@@ -57,6 +57,7 @@ typedef enum {
   WEB_EXTENSION_ERROR_NOT_IMPLEMENTED = 1003,
   WEB_EXTENSION_ERROR_INVALID_MANIFEST = 1004,
   WEB_EXTENSION_ERROR_INVALID_XPI = 1005,
+  WEB_EXTENSION_ERROR_INVALID_HOST = 1006,
 } WebExtensionErrorCode;
 
 typedef struct {
@@ -168,5 +169,8 @@ void                   ephy_web_extension_clear_local_storage             (EphyW
 char                  *ephy_web_extension_create_sender_object            (EphyWebExtension *self,
                                                                           WebKitWebView     *web_view);
 
+gboolean               ephy_web_extension_has_web_accessible_resource     (EphyWebExtension *self,
+                                                                           const char       *path);
+
 G_END_DECLS
 


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