Skip to content

Commit

Permalink
document-portal: Implement GetHostPaths
Browse files Browse the repository at this point in the history
This method allows apps to get path as exists on the host filesystem for
documents exported through the document portal.

This method takes a list of document IDs as a string array and returns
a dictionary mapping document IDs to the paths in the host filesystem.
It is expected an app making this request to have access to given list
of documents.

This is based on initial work made by @JakobDev

Fixes flatpak#475
  • Loading branch information
grulja committed May 27, 2024
1 parent ef1e96b commit 2b14a3d
Show file tree
Hide file tree
Showing 3 changed files with 158 additions and 2 deletions.
16 changes: 16 additions & 0 deletions data/org.freedesktop.portal.Documents.xml
Original file line number Diff line number Diff line change
Expand Up @@ -273,5 +273,21 @@
<arg type='s' name='app_id' direction='in'/>
<arg type='a{say}' name='docs' direction='out'/>
</method>

<!--
GetHostPaths:
@doc_id: the list of IDs of the files in the document store
@path: a dictionary mapping document IDs to the paths in the host filesystem
Gets the filesystem paths for document store entries.
This call is available inside the sandbox, if the application has the permission for the documents.
This method was added in version 5 of this interface.
-->
<method name="GetHostPaths">
<arg type='as' name='doc_ids' direction='in'/>
<arg type='a{say}' name='paths' direction='out'/>
</method>
</interface>
</node>
87 changes: 86 additions & 1 deletion document-portal/document-portal.c
Original file line number Diff line number Diff line change
Expand Up @@ -1416,6 +1416,90 @@ portal_list (GDBusMethodInvocation *invocation,
return TRUE;
}

const char *
get_host_path_internal (GDBusMethodInvocation *invocation,
XdpAppInfo *app_info,
const char *id)
{
g_autoptr(PermissionDbEntry) entry = NULL;

XDP_AUTOLOCK (db);

entry = permission_db_lookup (db, id);

if (!entry)
{
g_dbus_method_invocation_return_error (invocation,
XDG_DESKTOP_PORTAL_ERROR, XDG_DESKTOP_PORTAL_ERROR_INVALID_ARGUMENT,
g_strdup_printf("Invalid ID passed (%s)", id));
return NULL;
}

if (!xdp_app_info_is_host (app_info))
{
g_autofree const char **apps = NULL;
const char *app_id = NULL;
gboolean app_found = FALSE;
int i;

app_id = xdp_app_info_get_id(app_info);

apps = permission_db_entry_list_apps (entry);
for (i = 0; apps[i] != NULL; i++)
{
if (g_strcmp0 (app_id, apps[i]) == 0)
{
app_found = TRUE;
break;
}
}

if (!app_found)
{
g_dbus_method_invocation_return_error (invocation,
XDG_DESKTOP_PORTAL_ERROR, XDG_DESKTOP_PORTAL_ERROR_NOT_ALLOWED,
"Not enough permissions");
return NULL;
}
}

g_autoptr (GVariant) data = permission_db_entry_get_data (entry);
const char *path;

g_variant_get (data, "(^&ayttu)", &path, NULL, NULL, NULL);

return path;
}

static gboolean
portal_get_host_paths (GDBusMethodInvocation *invocation,
GVariant *parameters,
XdpAppInfo *app_info)
{
g_autofree const char **id_list = NULL;
const char *path;

g_variant_get (parameters, "(^a&s)", &id_list);

GVariantBuilder builder = G_VARIANT_BUILDER_INIT (G_VARIANT_TYPE ("a{say}"));

for (size_t i = 0; id_list[i] != NULL; i++)
{
path = get_host_path_internal (invocation, app_info, id_list[i]);
if (path == NULL)
{
g_variant_builder_clear (&builder);
return FALSE;
}

g_variant_builder_add (&builder, "{s@ay}", id_list[i], g_variant_new_bytestring (path));
}

g_dbus_method_invocation_return_value (invocation, g_variant_new ("(@a{say})", g_variant_builder_end (&builder)));;

return TRUE;
}

static void
peer_died_cb (const char *name)
{
Expand All @@ -1432,7 +1516,7 @@ on_bus_acquired (GDBusConnection *connection,

dbus_api = xdp_dbus_documents_skeleton_new ();

xdp_dbus_documents_set_version (XDP_DBUS_DOCUMENTS (dbus_api), 4);
xdp_dbus_documents_set_version (XDP_DBUS_DOCUMENTS (dbus_api), 5);

g_signal_connect_swapped (dbus_api, "handle-get-mount-point", G_CALLBACK (handle_get_mount_point), NULL);
g_signal_connect_swapped (dbus_api, "handle-add", G_CALLBACK (handle_method), portal_add);
Expand All @@ -1445,6 +1529,7 @@ on_bus_acquired (GDBusConnection *connection,
g_signal_connect_swapped (dbus_api, "handle-lookup", G_CALLBACK (handle_method), portal_lookup);
g_signal_connect_swapped (dbus_api, "handle-info", G_CALLBACK (handle_method), portal_info);
g_signal_connect_swapped (dbus_api, "handle-list", G_CALLBACK (handle_method), portal_list);
g_signal_connect_swapped (dbus_api, "handle-get-host-paths", G_CALLBACK (handle_method), portal_get_host_paths);

file_transfer = file_transfer_create ();
g_dbus_interface_skeleton_set_flags (file_transfer,
Expand Down
57 changes: 56 additions & 1 deletion tests/test-doc-portal.c
Original file line number Diff line number Diff line change
Expand Up @@ -687,6 +687,60 @@ test_add_named (void)
assert_doc_not_exist (id1, basename1, "com.test.App2");
}

static void
test_get_host_paths (void)
{
g_autofree char *doc_id = NULL;
g_autofree char *expected_real_path = NULL;
g_autofree char *real_path = NULL;
const char *basename = "host-path";
g_autoptr(GVariant) path= NULL;
g_autoptr(GVariant) reply = NULL;
g_autoptr(GVariant) result = NULL;
g_autoptr(GVariantIter) iter = NULL;
GVariant *args = NULL;
GError *error = NULL;
const gchar* key = NULL;

if (!check_fuse_or_skip_test ())
return;

doc_id = export_new_file (basename, "content", FALSE);

GVariantBuilder builder;
g_variant_builder_init (&builder, G_VARIANT_TYPE ("(as)"));
GVariantBuilder arrayBuilder;
g_variant_builder_init (&arrayBuilder, G_VARIANT_TYPE ("as"));
g_variant_builder_add (&arrayBuilder, "s", doc_id);
g_variant_builder_add_value (&builder, g_variant_builder_end (&arrayBuilder));

args = g_variant_builder_end (&builder);

reply = g_dbus_connection_call_sync (session_bus,
"org.freedesktop.portal.Documents",
"/org/freedesktop/portal/documents",
"org.freedesktop.portal.Documents",
"GetHostPaths", args,
G_VARIANT_TYPE ("(a{say})"),
0, -1,
NULL,
&error);

g_assert_no_error (error);
result = g_variant_get_child_value (reply, 0);

g_assert (g_variant_is_of_type (result, G_VARIANT_TYPE ("a{say}")));

expected_real_path = g_build_filename (outdir, basename, NULL);
iter = g_variant_iter_new (result);
while (g_variant_iter_loop (iter, "{&s@ay}", &key, &path)) {
if (g_strcmp0 (key, doc_id) == 0) {
g_assert_cmpstr (g_variant_get_bytestring (path), ==, expected_real_path);
return;
}
}
}

static void
global_setup (void)
{
Expand Down Expand Up @@ -853,7 +907,7 @@ test_version (void)
if (!check_fuse_or_skip_test ())
return;

g_assert_cmpint (xdp_dbus_documents_get_version (documents), ==, 4);
g_assert_cmpint (xdp_dbus_documents_get_version (documents), ==, 5);
}

int
Expand All @@ -871,6 +925,7 @@ main (int argc, char **argv)
g_test_add_func ("/db/recursive_doc", test_recursive_doc);
g_test_add_func ("/db/create_docs", test_create_docs);
g_test_add_func ("/db/add_named", test_add_named);
g_test_add_func ("/db/get_host_paths", test_get_host_paths);

global_setup ();

Expand Down

0 comments on commit 2b14a3d

Please sign in to comment.