system-helper: Add RemoveLocalRef helper function

This depends on the modify-repo privilege

Closes: #1034
Approved by: alexlarsson
This commit is contained in:
Sam Spilsbury 2017-09-26 09:45:57 +08:00 committed by Atomic Bot
parent 6236a60a1b
commit 3f91b4d883
5 changed files with 200 additions and 55 deletions

View File

@ -6974,10 +6974,36 @@ flatpak_dir_remove_ref (FlatpakDir *self,
GCancellable *cancellable,
GError **error)
{
if (!ostree_repo_set_ref_immediate (self->repo, remote_name, ref, NULL, cancellable, error))
if (flatpak_dir_use_system_helper (self, NULL))
{
const char *installation = flatpak_dir_get_id (self);
FlatpakSystemHelper *system_helper = flatpak_dir_get_system_helper (self);
/* If we don't have the system helper, we'll have to try and just remove
* the ref as an unprivileged user, which might fail later */
if (system_helper)
{
if (!flatpak_system_helper_call_remove_local_ref_sync (system_helper,
remote_name,
ref,
installation ? installation : "",
cancellable,
error))
return FALSE;
}
return TRUE;
}
if (!ostree_repo_set_ref_immediate (self->repo,
remote_name,
ref,
NULL,
cancellable,
error))
return FALSE;
return TRUE;
return flatpak_dir_prune (self, cancellable, error);
}
gboolean
@ -7033,58 +7059,6 @@ out:
return ret;
}
static GHashTable *
filter_out_deployed_refs (FlatpakDir *self,
GHashTable *local_refs)
{
GHashTable *undeployed_refs = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, NULL);
g_autoptr(GVariant) deploy_data = NULL;
GHashTableIter hash_iter;
gpointer key;
g_hash_table_iter_init (&hash_iter, local_refs);
while (g_hash_table_iter_next (&hash_iter, &key, NULL))
{
g_autoptr(GVariant) deploy_data = flatpak_dir_get_deploy_data (self, key, NULL, NULL);
if (!deploy_data)
g_hash_table_add (undeployed_refs, g_strdup (key));
}
return undeployed_refs;
}
gboolean
flatpak_dir_cleanup_undeployed_refs (FlatpakDir *self,
GCancellable *cancellable,
GError **error)
{
g_autoptr(GHashTable) local_refs = NULL;
g_autoptr(GHashTable) undeployed_refs = NULL;
GHashTableIter hash_iter;
gpointer key;
if (!ostree_repo_list_refs (self->repo, NULL, &local_refs, cancellable, error))
return FALSE;
undeployed_refs = filter_out_deployed_refs (self, local_refs);
g_hash_table_iter_init (&hash_iter, undeployed_refs);
while (g_hash_table_iter_next (&hash_iter, &key, NULL))
{
g_autofree gchar *remote = NULL;
g_autofree gchar *ref = NULL;
if (!ostree_parse_refspec (key, &remote, &ref, error))
return FALSE;
if (!flatpak_dir_remove_ref (self, remote, ref, cancellable, error))
return FALSE;
}
return TRUE;
}
gboolean
flatpak_dir_prune (FlatpakDir *self,
GCancellable *cancellable,
@ -8055,6 +8029,101 @@ flatpak_dir_find_installed_ref (FlatpakDir *self,
return NULL;
}
/* Given a list of refs in local_refspecs, remove any refs that have already
* been deployed and return a new GPtrArray containing only the undeployed
* refs. This is used by flatpak_dir_cleanup_undeployed_refs to determine
* which undeployed refs need to be removed from the local repository.
*
* Returns: (transfer-full): A #GPtrArray
*/
static GPtrArray *
filter_out_deployed_refs (FlatpakDir *self,
GPtrArray *local_refspecs,
GError **error)
{
g_autoptr(GPtrArray) undeployed_refs = g_ptr_array_new_full (local_refspecs->len, g_free);
gsize i;
for (i = 0; i < local_refspecs->len; ++i)
{
const gchar *refspec = g_ptr_array_index (local_refspecs, i);
g_autofree gchar *ref = NULL;
g_autoptr(GVariant) deploy_data = NULL;
if (!ostree_parse_refspec (refspec, NULL, &ref, error))
return FALSE;
deploy_data = flatpak_dir_get_deploy_data (self, ref, NULL, NULL);
if (!deploy_data)
g_ptr_array_add (undeployed_refs, g_strdup (refspec));
}
return g_steal_pointer (&undeployed_refs);
}
/**
* flatpak_dir_cleanup_undeployed_refs:
*
* Find all flatpak refs in the local repository which have not been deloyed
* in the dir and remove them from the repository. You might want to call this
* function if you pulled refs into the dir but then decided that you did
* not want to deploy them for some reason. Note that this does not prune
* objects bound to the cleaned up refs from the underlying OSTree repository,
* you should consider using flatpak_dir_prune to do that.
*
* @self: a #FlatpakDir
* @cancellable: (allow-none): a #GCancellable
* @error: (allow-none): a #GError
*
* Since: 0.10.0
* Returns: (transfer-full): %TRUE if cleaning up the refs suceeded, %FALSE
* otherwise
*/
gboolean
flatpak_dir_cleanup_undeployed_refs (FlatpakDir *self,
GCancellable *cancellable,
GError **error)
{
g_autoptr(GHashTable) local_refspecs = NULL;
g_autoptr(GPtrArray) local_flatpak_refspecs = NULL;
g_autoptr(GPtrArray) undeployed_refs = NULL;
gsize i = 0;
if (!ostree_repo_list_refs (self->repo, NULL, &local_refspecs, cancellable, error))
return FALSE;
local_flatpak_refspecs = find_matching_refs (local_refspecs,
NULL, NULL, NULL,
FLATPAK_KINDS_APP |
FLATPAK_KINDS_RUNTIME,
FIND_MATCHING_REFS_FLAGS_KEEP_REMOTE,
error);
if (!local_flatpak_refspecs)
return FALSE;
undeployed_refs = filter_out_deployed_refs (self, local_flatpak_refspecs, error);
if (!undeployed_refs)
return FALSE;
for (; i < undeployed_refs->len; ++i)
{
const char *refspec = g_ptr_array_index (undeployed_refs, i);
g_autofree gchar *remote = NULL;
g_autofree gchar *ref = NULL;
if (!ostree_parse_refspec (refspec, &remote, &ref, error))
return FALSE;
if (!flatpak_dir_remove_ref (self, remote, ref, cancellable, error))
return FALSE;
}
return TRUE;
}
static FlatpakDir *
flatpak_dir_new_full (GFile *path, gboolean user, DirExtraData *extra_data)
{

View File

@ -111,6 +111,12 @@
<arg type='ay' name='summary_sig_path' direction='in'/>
</method>
<method name="RemoveLocalRef">
<arg type='s' name='remote' direction='in'/>
<arg type='s' name='ref' direction='in'/>
<arg type='s' name='installation' direction='in'/>
</method>
</interface>
</node>

View File

@ -790,6 +790,49 @@ handle_update_remote (FlatpakSystemHelper *object,
return TRUE;
}
static gboolean
handle_remove_local_ref (FlatpakSystemHelper *object,
GDBusMethodInvocation *invocation,
const gchar *arg_remote,
const gchar *arg_ref,
const gchar *arg_installation)
{
g_autoptr(FlatpakDir) system = NULL;
g_autoptr(GError) error = NULL;
g_debug ("RemoveLocalRef %s %s %s", arg_remote, arg_ref, arg_installation);
system = dir_get_system (arg_installation, &error);
if (system == NULL)
{
g_dbus_method_invocation_return_gerror (invocation, error);
return TRUE;
}
if (*arg_remote == 0 || strchr (arg_remote, '/') != NULL)
{
g_dbus_method_invocation_return_error (invocation, G_DBUS_ERROR, G_DBUS_ERROR_INVALID_ARGS,
"Invalid remote name: %s", arg_remote);
return TRUE;
}
if (!flatpak_dir_ensure_repo (system, NULL, &error))
{
g_dbus_method_invocation_return_gerror (invocation, error);
return TRUE;
}
if (!flatpak_dir_remove_ref (system, arg_remote, arg_ref, NULL, &error))
{
g_dbus_method_invocation_return_gerror (invocation, error);
return TRUE;
}
flatpak_system_helper_complete_remove_local_ref (object, invocation);
return TRUE;
}
static gboolean
flatpak_authorize_method_handler (GDBusInterfaceSkeleton *interface,
GDBusMethodInvocation *invocation,
@ -901,6 +944,16 @@ flatpak_authorize_method_handler (GDBusInterfaceSkeleton *interface,
action = "org.freedesktop.Flatpak.update-remote";
polkit_details_insert (details, "remote", remote);
}
else if (g_strcmp0 (method_name, "RemoveLocalRef") == 0)
{
const char *remote;
g_variant_get_child (parameters, 0, "&s", &remote);
action = "org.freedesktop.Flatpak.modify-repo";
polkit_details_insert (details, "remote", remote);
}
@ -958,6 +1011,7 @@ on_bus_acquired (GDBusConnection *connection,
g_signal_connect (helper, "handle-install-bundle", G_CALLBACK (handle_install_bundle), NULL);
g_signal_connect (helper, "handle-configure-remote", G_CALLBACK (handle_configure_remote), NULL);
g_signal_connect (helper, "handle-update-remote", G_CALLBACK (handle_update_remote), NULL);
g_signal_connect (helper, "handle-remove-local-ref", G_CALLBACK (handle_remove_local_ref), NULL);
g_signal_connect (helper, "g-authorize-method",
G_CALLBACK (flatpak_authorize_method_handler),

View File

@ -98,6 +98,21 @@
</defaults>
</action>
<action id="org.freedesktop.Flatpak.modify-repo">
<!-- SECURITY:
- Normal users do not need authentication to modify the
OSTree repository
-->
<description>Update system repository</description>
<message>Authentication is required to update the system repository</message>
<icon_name>package-x-generic</icon_name>
<defaults>
<allow_any>auth_admin</allow_any>
<allow_inactive>auth_admin</allow_inactive>
<allow_active>yes</allow_active>
</defaults>
</action>
<action id="org.freedesktop.Flatpak.install-bundle">
<description>Install bundle</description>
<message>Authentication is required to install software</message>

View File

@ -2,7 +2,8 @@ polkit.addRule(function(action, subject) {
if ((action.id == "org.freedesktop.Flatpak.app-install" ||
action.id == "org.freedesktop.Flatpak.runtime-install"||
action.id == "org.freedesktop.Flatpak.app-uninstall" ||
action.id == "org.freedesktop.Flatpak.runtime-uninstall") &&
action.id == "org.freedesktop.Flatpak.runtime-uninstall" ||
action.id == "org.freedesktop.Flatpak.modify-repo") &&
subject.active == true && subject.local == true &&
subject.isInGroup("@privileged_group@")) {
return polkit.Result.YES;