[gnome-control-center] notifications: Forward notification settings to portal



commit 8b9be45cba0a9f973489f16d464d235451501080
Author: Matthias Clasen <mclasen redhat com>
Date:   Wed Feb 22 06:57:14 2017 -0500

    notifications: Forward notification settings to portal
    
    The flatpak notification portal reads permissions out
    of the permission store, so forward the notification
    permissions there in order to prevent sandboxed
    applications from sending notifications.
    
    The difference is a bit cosmetic, since the shell would
    not show the notification anyway in this case, but it
    is nicer to just cut off the calls and not let them
    through the portal in the first place.
    
    https://bugzilla.gnome.org/show_bug.cgi?id=778851

 panels/notifications/cc-edit-dialog.c         |  136 ++++++++++++++++++++++++-
 panels/notifications/cc-edit-dialog.h         |    3 +-
 panels/notifications/cc-notifications-panel.c |   38 +++++++-
 3 files changed, 174 insertions(+), 3 deletions(-)
---
diff --git a/panels/notifications/cc-edit-dialog.c b/panels/notifications/cc-edit-dialog.c
index a06601d..778c18c 100644
--- a/panels/notifications/cc-edit-dialog.c
+++ b/panels/notifications/cc-edit-dialog.c
@@ -49,6 +49,33 @@ static void update_sound_switch (GtkWidget *dialog);
 static void update_notification_switch (GtkWidget *dialog);
 static void update_switches (GtkWidget *dialog);
 
+static void
+dialog_set_app_id (GtkWidget *dialog,
+                   const char *app_id)
+{
+  g_object_set_data_full (G_OBJECT (dialog), "app-id", g_strdup (app_id), g_free);
+}
+
+static const char *
+dialog_get_app_id (GtkWidget *dialog)
+{
+  return (const char*)g_object_get_data (G_OBJECT (dialog), "app-id");
+}
+
+static void
+dialog_set_perm_store (GtkWidget  *dialog,
+                       GDBusProxy *proxy)
+{
+  if (proxy)
+    g_object_set_data_full (G_OBJECT (dialog), "perm-store", g_object_ref (proxy), g_object_unref);
+}
+
+static GDBusProxy *
+dialog_get_perm_store (GtkWidget *dialog)
+{
+  return (GDBusProxy *)g_object_get_data (G_OBJECT (dialog), "perm-store");
+}
+
 static GtkWidget *
 get_switch (GtkBuilder  *builder,
             const gchar *prefix)
@@ -76,11 +103,108 @@ set_key_from_switch (GtkWidget   *dialog,
 }
 
 static void
+on_perm_store_set_done (GObject *source_object,
+                        GAsyncResult *res,
+                        gpointer user_data)
+{
+  g_autoptr(GVariant) results = NULL;
+  g_autoptr(GError) error = NULL;
+
+  results = g_dbus_proxy_call_finish (G_DBUS_PROXY (source_object),
+                                      res,
+                                      &error);
+  if (results == NULL)
+    {
+      if (!g_error_matches (error, G_IO_ERROR, G_IO_ERROR_CANCELLED))
+        g_warning ("Failed to store permissions: %s", error->message);
+      return;
+    }
+}
+
+static void
+set_portal_permissions_for_app (GtkWidget *dialog, GtkSwitch *the_switch)
+{
+  GDBusProxy *perm_store = dialog_get_perm_store (dialog);
+  const char *app_id = dialog_get_app_id (dialog);
+  gboolean allow = gtk_switch_get_active (the_switch);
+  g_autoptr(GVariant) perms = NULL;
+  g_autoptr(GVariant) new_perms = NULL;
+  g_autoptr(GVariant) data = NULL;
+  GVariantBuilder builder;
+  gboolean found;
+  int i;
+  const char *yes_strv[] = { "yes", NULL };
+  const char *no_strv[] = { "no", NULL };
+  g_autoptr(GVariant) reply = NULL;
+  g_autoptr(GError) error = NULL;
+
+  if (perm_store == NULL)
+    {
+      g_warning ("Could not find PermissionStore, not syncing notification permissions");
+      return;
+    }
+
+  new_perms = g_variant_new_strv (allow ? yes_strv : no_strv, 1);
+  g_variant_ref_sink (new_perms);
+
+  g_variant_builder_init (&builder, G_VARIANT_TYPE("a{sas}"));
+  found = FALSE;
+
+  reply = g_dbus_proxy_call_sync (perm_store,
+                                  "Lookup",
+                                  g_variant_new ("(ss)",
+                                                 "notifications",
+                                                 "notification"),
+                                  G_DBUS_CALL_FLAGS_NONE,
+                                  -1,
+                                  NULL,
+                                  NULL);
+  if (reply)
+    {
+      g_variant_get (reply, "(@a{sas}v)", &perms, &data);
+
+      for (i = 0; i < g_variant_n_children (perms); i++)
+        {
+          const char *key;
+          g_autoptr(GVariant) value = NULL;
+
+          g_variant_get_child (perms, i, "{&s@as}", &key, &value);
+          if (g_strcmp0 (key, app_id) == 0)
+            {
+              found = TRUE;
+              g_variant_builder_add (&builder, "{s@as}", key, new_perms);
+            }
+          else
+            g_variant_builder_add (&builder, "{s@as}", key, value);
+        }
+    }
+
+  if (!found)
+    g_variant_builder_add (&builder, "{s@as}", app_id, new_perms);
+
+
+  g_dbus_proxy_call (perm_store,
+                     "Set",
+                     g_variant_new ("(sbsa{sas}v)",
+                                    "notifications",
+                                    TRUE,
+                                    "notification",
+                                    &builder,
+                                    data ? data : g_variant_new_byte (0)),
+                     G_DBUS_CALL_FLAGS_NONE,
+                     -1,
+                     NULL,
+                     on_perm_store_set_done,
+                     data);
+}
+
+static void
 notifications_switch_state_set_cb (GtkSwitch  *widget,
                                    GParamSpec *pspec,
                                    GtkWidget  *dialog)
 {
   set_key_from_switch (dialog, "enable", widget);
+  set_portal_permissions_for_app (dialog, widget);
   update_sound_switch (dialog);
   update_banner_switch (dialog);
   update_banner_content_switch (dialog);
@@ -303,7 +427,8 @@ void
 cc_build_edit_dialog (CcNotificationsPanel *panel,
                       GAppInfo             *app,
                       GSettings            *settings,
-                      GSettings            *master_settings)
+                      GSettings            *master_settings,
+                      GDBusProxy           *perm_store)
 {
   GtkBuilder *builder;
   GtkWindow  *shell;
@@ -312,6 +437,7 @@ cc_build_edit_dialog (CcNotificationsPanel *panel,
   GError     *error = NULL;
   gchar      *objects[] = { "edit-dialog", NULL };
   guint       builder_result;
+  char *app_id;
 
   builder = gtk_builder_new ();
   builder_result = gtk_builder_add_objects_from_resource (builder,
@@ -331,6 +457,14 @@ cc_build_edit_dialog (CcNotificationsPanel *panel,
 
   dialog = GTK_WIDGET (gtk_builder_get_object (builder, "edit-dialog"));
 
+  app_id = g_strdup (g_app_info_get_id (app));
+  if (g_str_has_suffix (app_id, ".desktop"))
+    app_id[strlen (app_id) - strlen (".desktop")] = '\0';
+  dialog_set_app_id (dialog, app_id);
+  g_free (app_id);
+
+  dialog_set_perm_store (dialog, perm_store);
+
   g_object_set (dialog,
                 "title", g_app_info_get_name (app),
                 "transient-for", shell,
diff --git a/panels/notifications/cc-edit-dialog.h b/panels/notifications/cc-edit-dialog.h
index fdd73ac..c0dc274 100644
--- a/panels/notifications/cc-edit-dialog.h
+++ b/panels/notifications/cc-edit-dialog.h
@@ -27,7 +27,8 @@ G_BEGIN_DECLS
 void cc_build_edit_dialog (CcNotificationsPanel *panel,
                            GAppInfo             *app,
                            GSettings            *settings,
-                           GSettings            *master_settings);
+                           GSettings            *master_settings,
+                           GDBusProxy           *perm_store);
 
 G_END_DECLS
 
diff --git a/panels/notifications/cc-notifications-panel.c b/panels/notifications/cc-notifications-panel.c
index a0c24b1..8cadb99 100644
--- a/panels/notifications/cc-notifications-panel.c
+++ b/panels/notifications/cc-notifications-panel.c
@@ -48,6 +48,8 @@ struct _CcNotificationsPanel {
 
   GList *sections;
   GList *sections_reverse;
+
+  GDBusProxy *perm_store;
 };
 
 struct _CcNotificationsPanelClass {
@@ -93,6 +95,7 @@ cc_notifications_panel_finalize (GObject *object)
   CcNotificationsPanel *panel = CC_NOTIFICATIONS_PANEL (object);
 
   g_clear_object (&panel->apps_load_cancellable);
+  g_clear_object (&panel->perm_store);
 
   G_OBJECT_CLASS (cc_notifications_panel_parent_class)->finalize (object);
 }
@@ -139,6 +142,29 @@ keynav_failed (GtkWidget            *widget,
 }
 
 static void
+on_perm_store_ready (GObject *source_object,
+                     GAsyncResult *res,
+                     gpointer user_data)
+{
+  CcNotificationsPanel *self;
+  GDBusProxy *proxy;
+  GError *error = NULL;
+
+  proxy = g_dbus_proxy_new_for_bus_finish (res, &error);
+  if (proxy == NULL)
+    {
+      if (!g_error_matches (error, G_IO_ERROR, G_IO_ERROR_CANCELLED))
+          g_warning ("Failed to connect to xdg-app permission store: %s",
+                     error->message);
+      g_error_free (error);
+
+      return;
+    }
+  self = user_data;
+  self->perm_store = proxy;
+}
+
+static void
 cc_notifications_panel_init (CcNotificationsPanel *panel)
 {
   GtkWidget *w;
@@ -214,6 +240,16 @@ cc_notifications_panel_init (CcNotificationsPanel *panel)
   gtk_container_add (GTK_CONTAINER (panel), w);
 
   gtk_widget_show (w);
+
+  g_dbus_proxy_new_for_bus (G_BUS_TYPE_SESSION,
+                            G_DBUS_PROXY_FLAGS_NONE,
+                            NULL,
+                            "org.freedesktop.impl.portal.PermissionStore",
+                            "/org/freedesktop/impl/portal/PermissionStore",
+                            "org.freedesktop.impl.portal.PermissionStore",
+                            panel->apps_load_cancellable,
+                            on_perm_store_ready,
+                            panel);
 }
 
 static const char *
@@ -535,7 +571,7 @@ select_app (GtkListBox           *list_box,
   Application *app;
 
   app = g_object_get_qdata (G_OBJECT (row), application_quark ());
-  cc_build_edit_dialog (panel, app->app_info, app->settings, panel->master_settings);
+  cc_build_edit_dialog (panel, app->app_info, app->settings, panel->master_settings, panel->perm_store);
 }
 
 static void


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