[epiphany/wip/tingping/profile-migration: 1/5] Store web extension settings in a keyfile



commit 68c75602350426736aae2ad1a1d12f7474860a30
Author: Patrick Griffis <pgriffis igalia com>
Date:   Mon Dec 17 09:08:07 2018 -0500

    Store web extension settings in a keyfile
    
    When the WebKitGTK sandbox is enabled the web processes
    will not have access to DConf so these will not work.
    
    They do however have read access to our private directories
    so we can simply write a keyfile there and load them from the
    web extensions.
    
    The keyfile is simply kept in sync with the host DConf so all
    previous usage continues to work as expected.

 embed/web-extension/ephy-uri-tester.c    |   6 +-
 embed/web-extension/ephy-web-extension.c |   6 +-
 lib/ephy-settings.c                      | 111 +++++++++++++++++++++++++++++++
 lib/ephy-settings.h                      |  19 +++---
 4 files changed, 128 insertions(+), 14 deletions(-)
---
diff --git a/embed/web-extension/ephy-uri-tester.c b/embed/web-extension/ephy-uri-tester.c
index 5158dcb3a..76ea56f60 100644
--- a/embed/web-extension/ephy-uri-tester.c
+++ b/embed/web-extension/ephy-uri-tester.c
@@ -634,7 +634,7 @@ ephy_uri_tester_begin_loading_adblock_filters (EphyUriTester  *tester,
 {
   char **filters;
 
-  filters = g_settings_get_strv (EPHY_SETTINGS_MAIN, EPHY_PREFS_ADBLOCK_FILTERS);
+  filters = g_settings_get_strv (EPHY_SETTINGS_WEB_EXTENSION_MAIN, EPHY_PREFS_ADBLOCK_FILTERS);
   tester->adblock_filters_to_load = g_strv_length (filters);
   for (guint i = 0; filters[i]; i++) {
     GFile *filter_file;
@@ -852,7 +852,7 @@ ephy_uri_tester_load (EphyUriTester *tester)
 
   g_assert (EPHY_IS_URI_TESTER (tester));
 
-  if (!g_settings_get_boolean (EPHY_SETTINGS_WEB, EPHY_PREFS_WEB_ENABLE_ADBLOCK))
+  if (!g_settings_get_boolean (EPHY_SETTINGS_WEB_EXTENSION_WEB, EPHY_PREFS_WEB_ENABLE_ADBLOCK))
     tester->adblock_loaded = TRUE;
 
   if (tester->adblock_loaded)
@@ -871,6 +871,6 @@ ephy_uri_tester_load (EphyUriTester *tester)
                     G_CALLBACK (ephy_uri_tester_enable_adblock_changed_cb), tester);
   /* GSettings never emits the changed signal until after we read the setting
    * the first time after connecting the handler... work around this.*/
-  trash = g_settings_get_strv (EPHY_SETTINGS_MAIN, EPHY_PREFS_ADBLOCK_FILTERS);
+  trash = g_settings_get_strv (EPHY_SETTINGS_WEB_EXTENSION_MAIN, EPHY_PREFS_ADBLOCK_FILTERS);
   g_strfreev (trash);
 }
diff --git a/embed/web-extension/ephy-web-extension.c b/embed/web-extension/ephy-web-extension.c
index 4e11b600f..bebbebcef 100644
--- a/embed/web-extension/ephy-web-extension.c
+++ b/embed/web-extension/ephy-web-extension.c
@@ -103,7 +103,7 @@ should_use_adblocker (const char *request_uri,
                       const char *page_uri,
                       const char *redirected_request_uri)
 {
-  if (!g_settings_get_boolean (EPHY_SETTINGS_WEB, EPHY_PREFS_WEB_ENABLE_ADBLOCK))
+  if (!g_settings_get_boolean (EPHY_SETTINGS_WEB_EXTENSION_WEB, EPHY_PREFS_WEB_ENABLE_ADBLOCK))
     return FALSE;
 
   /* Always load the main resource... */
@@ -150,7 +150,7 @@ web_page_send_request (WebKitWebPage     *web_page,
   page_uri = webkit_web_page_get_uri (web_page);
   redirected_response_uri = redirected_response ? webkit_uri_response_get_uri (redirected_response) : NULL;
 
-  if (g_settings_get_boolean (EPHY_SETTINGS_WEB, EPHY_PREFS_WEB_DO_NOT_TRACK)) {
+  if (g_settings_get_boolean (EPHY_SETTINGS_WEB_EXTENSION_WEB, EPHY_PREFS_WEB_DO_NOT_TRACK)) {
     SoupMessageHeaders *headers = webkit_uri_request_get_http_headers (request);
     if (headers) {
       /* Do Not Track header. '1' means 'opt-out'. See:
@@ -275,7 +275,7 @@ web_page_form_controls_associated (WebKitWebPage    *web_page,
                                           G_TYPE_STRING, 2,
                                           G_TYPE_UINT64, G_TYPE_BOOLEAN);
   remember_passwords = !extension->is_private_profile &&
-                       g_settings_get_boolean (EPHY_SETTINGS_WEB, EPHY_PREFS_WEB_REMEMBER_PASSWORDS);
+                       g_settings_get_boolean (EPHY_SETTINGS_WEB_EXTENSION_WEB, 
EPHY_PREFS_WEB_REMEMBER_PASSWORDS);
   js_result = jsc_value_object_invoke_method (js_ephy,
                                               "formControlsAssociated",
                                               G_TYPE_UINT64, webkit_web_page_get_id (web_page),
diff --git a/lib/ephy-settings.c b/lib/ephy-settings.c
index 8c415a607..82f172efa 100644
--- a/lib/ephy-settings.c
+++ b/lib/ephy-settings.c
@@ -28,6 +28,9 @@
 #include <glib.h>
 #include <gio/gio.h>
 
+#define G_SETTINGS_ENABLE_BACKEND
+#include <gio/gsettingsbackend.h>
+
 static GHashTable *settings = NULL;
 
 static void
@@ -98,4 +101,112 @@ ephy_settings_get (const char *schema)
   return gsettings;
 }
 
+static void
+on_settings_changed (GSettings *settings,
+                     char      *key,
+                     gpointer   user_data)
+{
+  g_autoptr(GVariant) value = g_settings_get_user_value (settings, key);
+  if (value != NULL)
+    g_settings_set_value (user_data, key, value);
+  else
+    g_settings_reset (user_data, key);
+}
+
+/*
+ * This is to sync a host dconf settings schema with a keyfile based schema.
+ * The reason this is done is to continue supporting dconf usage on the host
+ * transparently.
+ */
+static void
+sync_settings (GSettings *original,
+               GSettings *new)
+{
+  g_autoptr(GSettingsSchema) schema = NULL;
+  g_auto(GStrv) keys = NULL;
+
+  g_object_get (original, "settings-schema", &schema, NULL);
+  keys = g_settings_schema_list_keys (schema);
+
+  for (size_t i = 0; keys[i] != NULL; ++i) {
+    const char *key = keys[i];
+    g_autoptr(GVariant) value = g_settings_get_user_value (original, key);
+
+    if (value != NULL)
+      g_settings_set_value (new, key, value);
+  }
+
+  g_signal_connect_object (original, "changed", G_CALLBACK (on_settings_changed), new, 0);
+}
+
+static char *
+get_relocatable_path (const char *schema)
+{
+  for (size_t i = 0; i < G_N_ELEMENTS (ephy_prefs_relocatable_schemas); i++) {
+    if (g_strcmp0 (ephy_prefs_relocatable_schemas[i].schema, schema) == 0)
+      return g_build_path ("/", "/org/gnome/epiphany/", ephy_prefs_relocatable_schemas[i].path, NULL);
+  }
+  return NULL;
+}
+
+/**
+ * ephy_settings_get_for_web_extension:
+ *
+ * Equivalent to ephy_settings_get() except it ensures that the
+ * settings backend is always keyfile based instead of using DConf.
+ *
+ * This is required because the WebKitGTK sandbox will not grant
+ * access to DConf but we do have access to our local directories.
+ * 
+ * It is also assumed this will only be used as read-only.
+ *
+ * Returns: (transfer none): #GSettings
+ */
+GSettings *
+ephy_settings_get_for_web_extension (const char *schema)
+{
+  GSettings *gsettings = NULL;
+  g_autofree char *key_name = NULL;
+
+  ephy_settings_init ();
+
+  // Web apps can't work with the sandbox anyway
+  const char *web_app_name = strstr (ephy_dot_dir (), EPHY_WEB_APP_PREFIX);
+  if (web_app_name != NULL)
+    return ephy_settings_get (schema);
+
+  key_name = g_strdup_printf ("keyfile-%s", schema);
+  gsettings = g_hash_table_lookup (settings, key_name);
+
+  if (gsettings == NULL) {
+    g_autoptr(GSettingsBackend) backend = NULL;
+    gsettings = ephy_settings_get (schema);
+    g_assert (gsettings != NULL);
+
+    // GLib inside Flatpak will default to this backend in the future
+    // so we don't need to do anything extra
+    g_object_get (gsettings, "backend", &backend, NULL);
+    // G_IS_KEYFILE_SETTINGS_BACKEND () is private API
+    if (!g_strcmp0 (g_type_name (G_TYPE_FROM_INSTANCE (backend)), "GKeyfileSettingsBackend")) {
+      g_hash_table_insert (settings, g_steal_pointer (&key_name), g_object_ref (gsettings));
+      return gsettings;
+    }
+
+    g_autofree char *keyfile_path = g_build_filename (ephy_dot_dir (), "web-extension-settings.ini", NULL);
+    backend = g_keyfile_settings_backend_new (keyfile_path, "/", "/");
+
+    GSettings *web_gsettings;
+    g_autofree char *path = get_relocatable_path (schema);
+    if (path != NULL)
+      web_gsettings = g_settings_new_with_backend_and_path (schema, backend, path);
+    else
+      web_gsettings = g_settings_new_with_backend (schema, backend);
+
+    sync_settings (gsettings, web_gsettings);
+    g_hash_table_insert (settings, g_steal_pointer (&key_name), web_gsettings);
+
+    return web_gsettings;
+  }
 
+  return gsettings;
+}
diff --git a/lib/ephy-settings.h b/lib/ephy-settings.h
index 48ed7fcc2..5c95f70d2 100644
--- a/lib/ephy-settings.h
+++ b/lib/ephy-settings.h
@@ -27,16 +27,19 @@
 
 G_BEGIN_DECLS
 
-#define EPHY_SETTINGS_MAIN      ephy_settings_get (EPHY_PREFS_SCHEMA)
-#define EPHY_SETTINGS_UI        ephy_settings_get (EPHY_PREFS_UI_SCHEMA)
-#define EPHY_SETTINGS_WEB       ephy_settings_get (EPHY_PREFS_WEB_SCHEMA)
-#define EPHY_SETTINGS_LOCKDOWN  ephy_settings_get (EPHY_PREFS_LOCKDOWN_SCHEMA)
-#define EPHY_SETTINGS_STATE     ephy_settings_get (EPHY_PREFS_STATE_SCHEMA)
-#define EPHY_SETTINGS_SYNC      ephy_settings_get (EPHY_PREFS_SYNC_SCHEMA)
-#define EPHY_SETTINGS_WEB_APP   ephy_settings_get (EPHY_PREFS_WEB_APP_SCHEMA)
-#define EPHY_SETTINGS_READER    ephy_settings_get (EPHY_PREFS_READER_SCHEMA)
+#define EPHY_SETTINGS_MAIN               ephy_settings_get (EPHY_PREFS_SCHEMA)
+#define EPHY_SETTINGS_UI                 ephy_settings_get (EPHY_PREFS_UI_SCHEMA)
+#define EPHY_SETTINGS_WEB                ephy_settings_get (EPHY_PREFS_WEB_SCHEMA)
+#define EPHY_SETTINGS_LOCKDOWN           ephy_settings_get (EPHY_PREFS_LOCKDOWN_SCHEMA)
+#define EPHY_SETTINGS_STATE              ephy_settings_get (EPHY_PREFS_STATE_SCHEMA)
+#define EPHY_SETTINGS_SYNC               ephy_settings_get (EPHY_PREFS_SYNC_SCHEMA)
+#define EPHY_SETTINGS_WEB_APP            ephy_settings_get (EPHY_PREFS_WEB_APP_SCHEMA)
+#define EPHY_SETTINGS_READER             ephy_settings_get (EPHY_PREFS_READER_SCHEMA)
+#define EPHY_SETTINGS_WEB_EXTENSION_MAIN ephy_settings_get_for_web_extension (EPHY_PREFS_SCHEMA)
+#define EPHY_SETTINGS_WEB_EXTENSION_WEB  ephy_settings_get_for_web_extension (EPHY_PREFS_WEB_SCHEMA)
 
 GSettings *ephy_settings_get (const char *schema);
+GSettings *ephy_settings_get_for_web_extension (const char *schema);
 
 void ephy_settings_shutdown (void);
 


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