Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Screenshot permission, attempt 2 #853

Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
13 changes: 13 additions & 0 deletions data/org.freedesktop.impl.portal.Screenshot.xml
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,8 @@
@short_description: Screenshot portal backend interface

This screenshot portal lets sandboxed applications request a screenshot.

This documentation describes version 2 of this interface.
-->
<interface name="org.freedesktop.impl.portal.Screenshot">
<!--
Expand Down Expand Up @@ -52,6 +54,15 @@
Defaults to no.
</para></listitem>
</varlistentry>
<varlistentry>
<term>permission_store_checked b</term>
<listitem><para>
Hint whether the screenshot portal has checked the 'screenshot' permission for
the requesting app. Defaults to no.

This option was added in version 2 of this interface.
</para></listitem>
</varlistentry>
</variablelist>

The following results get returned via the @results vardict:
Expand Down Expand Up @@ -103,5 +114,7 @@
<annotation name="org.qtproject.QtDBus.QtTypeName.Out1" value="QVariantMap"/>
<arg type="a{sv}" name="results" direction="out"/>
</method>

<property name="version" type="u" access="read"/>
</interface>
</node>
194 changes: 172 additions & 22 deletions src/screenshot.c
Original file line number Diff line number Diff line change
Expand Up @@ -28,15 +28,21 @@
#include <sys/stat.h>
#include <fcntl.h>

#include <glib/gi18n.h>
#include <gio/gio.h>
#include <gio/gdesktopappinfo.h>

#include "screenshot.h"
#include "permissions.h"
#include "request.h"
#include "documents.h"
#include "xdp-dbus.h"
#include "xdp-impl-dbus.h"
#include "xdp-utils.h"

#define PERMISSION_TABLE "screenshot"
#define PERMISSION_ID "screenshot"

typedef struct _Screenshot Screenshot;
typedef struct _ScreenshotClass ScreenshotClass;

Expand All @@ -51,6 +57,7 @@ struct _ScreenshotClass
};

static XdpDbusImplScreenshot *impl;
static XdpDbusImplAccess *access_impl;
static Screenshot *screenshot;

GType screenshot_get_type (void) G_GNUC_CONST;
Expand All @@ -60,6 +67,19 @@ G_DEFINE_TYPE_WITH_CODE (Screenshot, screenshot, XDP_DBUS_TYPE_SCREENSHOT_SKELET
G_IMPLEMENT_INTERFACE (XDP_DBUS_TYPE_SCREENSHOT,
screenshot_iface_init));

static void
send_response (Request *request,
guint response,
GVariant *results)
{
if (request->exported)
{
g_debug ("sending response: %d", response);
xdp_dbus_request_emit_response (XDP_DBUS_REQUEST (request), response, results);
request_unexport (request);
}
}

static void
send_response_in_thread_func (GTask *task,
gpointer source_object,
Expand Down Expand Up @@ -123,13 +143,7 @@ send_response_in_thread_func (GTask *task,
}

out:
if (request->exported)
{
xdp_dbus_request_emit_response (XDP_DBUS_REQUEST (request),
response,
g_variant_builder_end (&results));
request_unexport (request);
}
send_response (request, response, g_variant_builder_end (&results));
}

static void
Expand Down Expand Up @@ -168,19 +182,118 @@ static XdpOptionKey screenshot_options[] = {
{ "interactive", G_VARIANT_TYPE_BOOLEAN, NULL }
};

static gboolean
handle_screenshot (XdpDbusScreenshot *object,
GDBusMethodInvocation *invocation,
const gchar *arg_parent_window,
GVariant *arg_options)
static void
handle_screenshot_in_thread_func (GTask *task,
gpointer source_object,
gpointer task_data,
GCancellable *cancellable)
{
Request *request = request_from_invocation (invocation);
Request *request = (Request *)task_data;
g_autoptr(GError) error = NULL;
g_autoptr(XdpDbusImplRequest) impl_request = NULL;
GVariantBuilder opt_builder;
Permission permission;
GVariant *options;
gboolean permission_store_checked = FALSE;
gboolean interactive;
const char *parent_window;
const char *app_id;

REQUEST_AUTOLOCK (request);

g_variant_builder_init (&opt_builder, G_VARIANT_TYPE_VARDICT);

app_id = xdp_app_info_get_id (request->app_info);
parent_window = ((const char *)g_object_get_data (G_OBJECT (request), "parent-window"));
options = ((GVariant *)g_object_get_data (G_OBJECT (request), "options"));

if (xdp_dbus_impl_screenshot_get_version (impl) < 2)
goto query_impl;

permission = get_permission_sync (app_id, PERMISSION_TABLE, PERMISSION_ID);

if (!g_variant_lookup (options, "interactive", "b", &interactive))
interactive = FALSE;

if (!interactive && permission != PERMISSION_YES)
{
g_autoptr(GVariant) access_results = NULL;
GVariantBuilder access_opt_builder;
g_autofree gchar *subtitle = NULL;
g_autofree gchar *title = NULL;
const gchar *body;
guint access_response = 2;

if (permission == PERMISSION_NO)
{
send_response (request, 2, g_variant_builder_end (&opt_builder));
return;
}

g_variant_builder_init (&access_opt_builder, G_VARIANT_TYPE_VARDICT);
g_variant_builder_add (&access_opt_builder, "{sv}",
"deny_label", g_variant_new_string (_("Deny")));
g_variant_builder_add (&access_opt_builder, "{sv}",
"grant_label", g_variant_new_string (_("Allow")));
g_variant_builder_add (&access_opt_builder, "{sv}",
"icon", g_variant_new_string ("applets-screenshooter-symbolic"));

if (g_strcmp0 (app_id, "") != 0)
{
g_autoptr(GDesktopAppInfo) info = NULL;
g_autofree gchar *id = NULL;
const gchar *name;

id = g_strconcat (app_id, ".desktop", NULL);
info = g_desktop_app_info_new (id);
name = g_app_info_get_display_name (G_APP_INFO (info));

title = g_strdup_printf (_("Allow %s to Take Screenshots?"), name);
subtitle = g_strdup_printf (_("%s wants to be able to take screenshots at any time."), name);
}
else
{
/* Note: this will set the wallpaper permission for all unsandboxed
* apps for which an app ID can't be determined.
*/
g_assert (xdp_app_info_is_host (request->app_info));
title = g_strdup (_("Allow Applications to Take Screenshots?"));
subtitle = g_strdup (_("An application wants to be able to take screenshots at any time."));
}

body = _("This permission can be changed at any time from the privacy settings.");

if (!xdp_dbus_impl_access_call_access_dialog_sync (access_impl,
request->id,
app_id,
parent_window,
title,
subtitle,
body,
g_variant_builder_end (&access_opt_builder),
&access_response,
&access_results,
NULL,
&error))
{
g_warning ("Failed to show access dialog: %s", error->message);
return;
}

if (permission == PERMISSION_UNSET)
set_permission_sync (app_id, PERMISSION_TABLE, PERMISSION_ID, access_response == 0 ? PERMISSION_YES : PERMISSION_NO);

if (access_response != 0)
{
send_response (request, 2, g_variant_builder_end (&opt_builder));
return;
}
}

permission_store_checked = TRUE;

query_impl:

impl_request =
xdp_dbus_impl_request_proxy_new_sync (g_dbus_proxy_get_connection (G_DBUS_PROXY (impl)),
G_DBUS_PROXY_FLAGS_NONE,
Expand All @@ -189,29 +302,58 @@ handle_screenshot (XdpDbusScreenshot *object,
NULL, &error);
if (!impl_request)
{
g_dbus_method_invocation_return_gerror (invocation, error);
return G_DBUS_METHOD_INVOCATION_HANDLED;
g_warning ("Failed to to create screenshot implementation proxy: %s", error->message);
send_response (request, 2, g_variant_builder_end (&opt_builder));
return;
}

request_set_impl_request (request, impl_request);
request_export (request, g_dbus_method_invocation_get_connection (invocation));

g_variant_builder_init (&opt_builder, G_VARIANT_TYPE_VARDICT);
xdp_filter_options (arg_options, &opt_builder,
xdp_filter_options (options, &opt_builder,
screenshot_options, G_N_ELEMENTS (screenshot_options),
NULL);
if (permission_store_checked)
{
g_variant_builder_add (&opt_builder, "{sv}", "permission_store_checked",
g_variant_new_boolean (TRUE));
}

g_debug ("Calling Screenshot with interactive=%d", interactive);
xdp_dbus_impl_screenshot_call_screenshot (impl,
request->id,
xdp_app_info_get_id (request->app_info),
arg_parent_window,
app_id,
parent_window,
g_variant_builder_end (&opt_builder),
NULL,
screenshot_done,
g_object_ref (request));

}

static gboolean
handle_screenshot (XdpDbusScreenshot *object,
GDBusMethodInvocation *invocation,
const gchar *arg_parent_window,
GVariant *arg_options)
{
Request *request = request_from_invocation (invocation);
g_autoptr(GTask) task = NULL;

g_debug ("Handle Screenshot");

g_object_set_data_full (G_OBJECT (request), "parent-window", g_strdup (arg_parent_window), g_free);
g_object_set_data_full (G_OBJECT (request),
"options",
g_variant_ref (arg_options),
(GDestroyNotify)g_variant_unref);

request_export (request, g_dbus_method_invocation_get_connection (invocation));
xdp_dbus_screenshot_complete_screenshot (object, invocation, request->id);

task = g_task_new (object, NULL, NULL, NULL);
g_task_set_task_data (task, g_object_ref (request), g_object_unref);
g_task_run_in_thread (task, handle_screenshot_in_thread_func);

return G_DBUS_METHOD_INVOCATION_HANDLED;
}

Expand Down Expand Up @@ -316,13 +458,14 @@ screenshot_class_init (ScreenshotClass *klass)

GDBusInterfaceSkeleton *
screenshot_create (GDBusConnection *connection,
const char *dbus_name)
const char *dbus_name_access,
const char *dbus_name_screenshot)
{
g_autoptr(GError) error = NULL;

impl = xdp_dbus_impl_screenshot_proxy_new_sync (connection,
G_DBUS_PROXY_FLAGS_NONE,
dbus_name,
dbus_name_screenshot,
DESKTOP_PORTAL_OBJECT_PATH,
NULL,
&error);
Expand All @@ -336,5 +479,12 @@ screenshot_create (GDBusConnection *connection,

screenshot = g_object_new (screenshot_get_type (), NULL);

access_impl = xdp_dbus_impl_access_proxy_new_sync (connection,
G_DBUS_PROXY_FLAGS_NONE,
dbus_name_access,
DESKTOP_PORTAL_OBJECT_PATH,
NULL,
&error);

return G_DBUS_INTERFACE_SKELETON (screenshot);
}
3 changes: 2 additions & 1 deletion src/screenshot.h
Original file line number Diff line number Diff line change
Expand Up @@ -23,4 +23,5 @@
#include <gio/gio.h>

GDBusInterfaceSkeleton * screenshot_create (GDBusConnection *connection,
const char *dbus_name);
const char *dbus_name_access,
const char *dbus_name_screenshot);
10 changes: 9 additions & 1 deletion src/wallpaper.c
Original file line number Diff line number Diff line change
Expand Up @@ -195,7 +195,7 @@ handle_set_wallpaper_in_thread_func (GTask *task,
else
{
g_autoptr(GDesktopAppInfo) info = NULL;
const gchar *id;
g_autofree gchar *id = NULL;
const gchar *name;

id = g_strconcat (app_id, ".desktop", NULL);
Expand Down Expand Up @@ -267,6 +267,14 @@ handle_set_wallpaper_in_thread_func (GTask *task,
g_dbus_proxy_get_name (G_DBUS_PROXY (impl)),
request->id,
NULL, &error);

if (!impl_request)
{
g_warning ("Failed to to create wallpaper implementation proxy: %s", error->message);
send_response (request, 2);
return;
}

request_set_impl_request (request, impl_request);

g_variant_builder_init (&opt_builder, G_VARIANT_TYPE_VARDICT);
Expand Down
12 changes: 7 additions & 5 deletions src/xdg-desktop-portal.c
Original file line number Diff line number Diff line change
Expand Up @@ -266,11 +266,6 @@ on_bus_acquired (GDBusConnection *connection,
export_portal_implementation (connection,
print_create (connection, implementation->dbus_name, lockdown));

implementation = find_portal_implementation ("org.freedesktop.impl.portal.Screenshot");
if (implementation != NULL)
export_portal_implementation (connection,
screenshot_create (connection, implementation->dbus_name));

implementation = find_portal_implementation ("org.freedesktop.impl.portal.Notification");
if (implementation != NULL)
export_portal_implementation (connection,
Expand All @@ -282,6 +277,13 @@ on_bus_acquired (GDBusConnection *connection,
inhibit_create (connection, implementation->dbus_name));

implementation = find_portal_implementation ("org.freedesktop.impl.portal.Access");
implementation2 = find_portal_implementation ("org.freedesktop.impl.portal.Screenshot");
if (implementation != NULL && implementation2 != NULL)
export_portal_implementation (connection,
screenshot_create (connection,
implementation->dbus_name,
implementation2->dbus_name));

implementation2 = find_portal_implementation ("org.freedesktop.impl.portal.Background");
if (implementation != NULL)
{
Expand Down
Loading