diff options
-rw-r--r-- | common/flatpak-dir.c | 162 | ||||
-rw-r--r-- | common/flatpak-dir.h | 6 | ||||
-rw-r--r-- | data/org.freedesktop.Flatpak.xml | 6 | ||||
-rw-r--r-- | system-helper/flatpak-system-helper.c | 92 | ||||
-rw-r--r-- | system-helper/org.freedesktop.Flatpak.policy.in | 18 |
5 files changed, 244 insertions, 40 deletions
diff --git a/common/flatpak-dir.c b/common/flatpak-dir.c index 4d41e04..9899618 100644 --- a/common/flatpak-dir.c +++ b/common/flatpak-dir.c @@ -39,6 +39,10 @@ #define NO_SYSTEM_HELPER ((FlatpakSystemHelper *) (gpointer) 1) +static OstreeRepo * flatpak_dir_create_system_child_repo (FlatpakDir *self, + GLnxLockFile *file_lock, + GError **error); + struct FlatpakDir { GObject parent; @@ -936,63 +940,36 @@ flatpak_dir_remove_all_refs (FlatpakDir *self, } gboolean -flatpak_dir_update_appstream (FlatpakDir *self, +flatpak_dir_deploy_appstream (FlatpakDir *self, const char *remote, const char *arch, gboolean *out_changed, - OstreeAsyncProgress *progress, GCancellable *cancellable, GError **error) { - g_autofree char *branch = NULL; - g_autofree char *remote_and_branch = NULL; - g_autofree char *old_checksum = NULL; - g_autofree char *new_checksum = NULL; - - g_autoptr(GFile) root = NULL; g_autoptr(GFile) appstream_dir = NULL; g_autoptr(GFile) remote_dir = NULL; g_autoptr(GFile) arch_dir = NULL; g_autoptr(GFile) checkout_dir = NULL; - g_autoptr(GFile) old_checkout_dir = NULL; - g_autoptr(GFileInfo) file_info = NULL; + g_autoptr(GFile) timestamp_file = NULL; g_autofree char *arch_path = NULL; + gboolean checkout_exists; + g_autofree char *remote_and_branch = NULL; + const char *old_checksum = NULL; + g_autofree char *new_checksum = NULL; + g_autoptr(GFile) active_link = NULL; + g_autoptr(GFileInfo) file_info = NULL; + g_autofree char *branch = NULL; + g_autoptr(GFile) root = NULL; + g_autoptr(GFile) old_checkout_dir = NULL; g_autofree char *tmpname = NULL; g_autoptr(GFile) active_tmp_link = NULL; - g_autoptr(GFile) active_link = NULL; - g_autoptr(GFile) timestamp_file = NULL; g_autoptr(GError) tmp_error = NULL; - gboolean checkout_exists; - - if (!flatpak_dir_ensure_repo (self, cancellable, error)) - return FALSE; - - if (arch == NULL) - arch = flatpak_get_arch (); - - branch = g_strdup_printf ("appstream/%s", arch); - remote_and_branch = g_strdup_printf ("%s:%s", remote, branch); - - if (!ostree_repo_resolve_rev (self->repo, remote_and_branch, TRUE, &old_checksum, error)) - return FALSE; - - if (!flatpak_dir_pull (self, remote, branch, NULL, NULL, OSTREE_REPO_PULL_FLAGS_NONE, progress, - cancellable, error)) - return FALSE; - - if (!ostree_repo_resolve_rev (self->repo, remote_and_branch, TRUE, &new_checksum, error)) - return FALSE; - - if (new_checksum == NULL) - { - g_warning ("No appstream branch in remote %s\n", remote); - return TRUE; - } appstream_dir = g_file_get_child (flatpak_dir_get_path (self), "appstream"); remote_dir = g_file_get_child (appstream_dir, remote); arch_dir = g_file_get_child (remote_dir, arch); - checkout_dir = g_file_get_child (arch_dir, new_checksum); + active_link = g_file_get_child (arch_dir, "active"); timestamp_file = g_file_get_child (arch_dir, ".timestamp"); arch_path = g_file_get_path (arch_dir); @@ -1002,6 +979,20 @@ flatpak_dir_update_appstream (FlatpakDir *self, return FALSE; } + old_checksum = NULL; + file_info = g_file_query_info (active_link, OSTREE_GIO_FAST_QUERYINFO, + G_FILE_QUERY_INFO_NOFOLLOW_SYMLINKS, + cancellable, NULL); + if (file_info != NULL) + old_checksum = g_file_info_get_symlink_target (file_info); + + branch = g_strdup_printf ("appstream/%s", arch); + remote_and_branch = g_strdup_printf ("%s:%s", remote, branch); + + if (!ostree_repo_resolve_rev (self->repo, remote_and_branch, TRUE, &new_checksum, error)) + return FALSE; + + checkout_dir = g_file_get_child (arch_dir, new_checksum); checkout_exists = g_file_query_exists (checkout_dir, NULL); if (old_checksum != NULL && new_checksum != NULL && @@ -1036,7 +1027,6 @@ flatpak_dir_update_appstream (FlatpakDir *self, tmpname = gs_fileutil_gen_tmp_name (".active-", NULL); active_tmp_link = g_file_get_child (arch_dir, tmpname); - active_link = g_file_get_child (arch_dir, "active"); if (!g_file_make_symbolic_link (active_tmp_link, new_checksum, cancellable, error)) return FALSE; @@ -1068,9 +1058,101 @@ flatpak_dir_update_appstream (FlatpakDir *self, if (out_changed) *out_changed = TRUE; + return TRUE; } +gboolean +flatpak_dir_update_appstream (FlatpakDir *self, + const char *remote, + const char *arch, + gboolean *out_changed, + OstreeAsyncProgress *progress, + GCancellable *cancellable, + GError **error) +{ + g_autofree char *branch = NULL; + g_autofree char *remote_and_branch = NULL; + g_autofree char *new_checksum = NULL; + + if (out_changed) + *out_changed = FALSE; + + if (arch == NULL) + arch = flatpak_get_arch (); + + branch = g_strdup_printf ("appstream/%s", arch); + + if (!flatpak_dir_ensure_repo (self, cancellable, error)) + return FALSE; + + if (flatpak_dir_use_child_repo (self)) + { + g_autoptr(OstreeRepo) child_repo = NULL; + g_auto(GLnxLockFile) child_repo_lock = GLNX_LOCK_FILE_INIT; + FlatpakSystemHelper *system_helper; + + child_repo = flatpak_dir_create_system_child_repo (self, &child_repo_lock, error); + if (child_repo == NULL) + return FALSE; + + system_helper = flatpak_dir_get_system_helper (self); + + g_assert (system_helper != NULL); + + if (!flatpak_dir_pull (self, remote, branch, NULL, + child_repo, OSTREE_REPO_PULL_FLAGS_MIRROR, + progress, cancellable, error)) + return FALSE; + + if (!ostree_repo_resolve_rev (child_repo, branch, TRUE, &new_checksum, error)) + return FALSE; + + if (new_checksum == NULL) + { + g_warning ("No appstream branch in remote %s\n", remote); + } + else + { + if (!flatpak_system_helper_call_deploy_appstream_sync (system_helper, + gs_file_get_path_cached (ostree_repo_get_path (child_repo)), + remote, + arch, + cancellable, + error)) + return FALSE; + } + + (void) glnx_shutil_rm_rf_at (AT_FDCWD, + gs_file_get_path_cached (ostree_repo_get_path (child_repo)), + NULL, NULL); + + return TRUE; + } + + if (!flatpak_dir_pull (self, remote, branch, NULL, NULL, OSTREE_REPO_PULL_FLAGS_NONE, progress, + cancellable, error)) + return FALSE; + + remote_and_branch = g_strdup_printf ("%s:%s", remote, branch); + + if (!ostree_repo_resolve_rev (self->repo, remote_and_branch, TRUE, &new_checksum, error)) + return FALSE; + + if (new_checksum == NULL) + { + g_warning ("No appstream branch in remote %s\n", remote); + return TRUE; + } + + return flatpak_dir_deploy_appstream (self, + remote, + arch, + out_changed, + cancellable, + error); +} + /* This is a copy of ostree_repo_pull_one_dir that always disables static deltas if subdir is used */ static gboolean diff --git a/common/flatpak-dir.h b/common/flatpak-dir.h index 495b81f..f40811f 100644 --- a/common/flatpak-dir.h +++ b/common/flatpak-dir.h @@ -165,6 +165,12 @@ gboolean flatpak_dir_remove_appstream (FlatpakDir *self, const char *remote, GCancellable *cancellable, GError **error); +gboolean flatpak_dir_deploy_appstream (FlatpakDir *self, + const char *remote, + const char *arch, + gboolean *out_changed, + GCancellable *cancellable, + GError **error); gboolean flatpak_dir_update_appstream (FlatpakDir *self, const char *remote, const char *arch, diff --git a/data/org.freedesktop.Flatpak.xml b/data/org.freedesktop.Flatpak.xml index e91cda3..8ef52bc 100644 --- a/data/org.freedesktop.Flatpak.xml +++ b/data/org.freedesktop.Flatpak.xml @@ -39,6 +39,12 @@ <arg type='s' name='origin' direction='in'/> <arg type='as' name='subpaths' direction='in'/> </method> + + <method name="DeployAppstream"> + <arg type='ay' name='repo_path' direction='in'/> + <arg type='s' name='origin' direction='in'/> + <arg type='s' name='arch' direction='in'/> + </method> </interface> </node> diff --git a/system-helper/flatpak-system-helper.c b/system-helper/flatpak-system-helper.c index 918d6b2..20a9e0e 100644 --- a/system-helper/flatpak-system-helper.c +++ b/system-helper/flatpak-system-helper.c @@ -158,6 +158,71 @@ handle_deploy (FlatpakSystemHelper *object, return TRUE; } +static gboolean +handle_deploy_appstream (FlatpakSystemHelper *object, + GDBusMethodInvocation *invocation, + const gchar *arg_repo_path, + const gchar *arg_origin, + const gchar *arg_arch) +{ + g_autoptr(FlatpakDir) system = flatpak_dir_get_system (); + g_autoptr(GFile) path = g_file_new_for_path (arg_repo_path); + g_autoptr(GError) error = NULL; + g_autoptr(GMainContext) main_context = NULL; + g_autofree char *branch = NULL; + + if (!g_file_query_exists (path, NULL)) + { + g_dbus_method_invocation_return_error (invocation, G_DBUS_ERROR, G_DBUS_ERROR_INVALID_ARGS, "Path does not exist"); + return TRUE; + } + + if (!flatpak_dir_ensure_repo (system, NULL, &error)) + { + g_dbus_method_invocation_return_error (invocation, G_DBUS_ERROR, G_DBUS_ERROR_FAILED, + "Can't open system repo %s", error->message); + return TRUE; + } + + /* Work around ostree-pull spinning the default main context for the sync calls */ + main_context = g_main_context_new (); + g_main_context_push_thread_default (main_context); + + branch = g_strdup_printf ("appstream/%s", arg_arch); + + g_print ("pulling branch %s\n", branch); + + if (!flatpak_dir_pull_untrusted_local (system, arg_repo_path, + arg_origin, + branch, + NULL, + NULL, + NULL, &error)) + { + g_main_context_pop_thread_default (main_context); + g_dbus_method_invocation_return_error (invocation, G_DBUS_ERROR, G_DBUS_ERROR_FAILED, + "Error pulling from repo: %s", error->message); + return TRUE; + } + + g_main_context_pop_thread_default (main_context); + + if (!flatpak_dir_deploy_appstream (system, + arg_origin, + arg_arch, + NULL, + NULL, + &error)) + { + g_dbus_method_invocation_return_error (invocation, G_DBUS_ERROR, G_DBUS_ERROR_FAILED, + "Error deploying appstream: %s", error->message); + return TRUE; + } + + flatpak_system_helper_complete_deploy_appstream (object, invocation); + + return TRUE; +} static gboolean flatpak_authorize_method_handler (GDBusInterfaceSkeleton *interface, @@ -229,6 +294,32 @@ flatpak_authorize_method_handler (GDBusInterfaceSkeleton *interface, authorized = polkit_authorization_result_get_is_authorized (result); } + else if (g_strcmp0 (method_name, "DeployAppstream") == 0) + { + const char *arch, *origin; + + g_variant_get_child (parameters, 1, "&s", &origin); + g_variant_get_child (parameters, 2, "&s", &arch); + + action = "org.freedesktop.Flatpak.appstream-update"; + + details = polkit_details_new (); + polkit_details_insert (details, "origin", origin); + polkit_details_insert (details, "arch", arch); + + result = polkit_authority_check_authorization_sync (authority, subject, + action, details, + POLKIT_CHECK_AUTHORIZATION_FLAGS_ALLOW_USER_INTERACTION, + NULL, &error); + if (result == NULL) + { + g_dbus_method_invocation_return_error (invocation, G_DBUS_ERROR, G_DBUS_ERROR_FAILED, + "Authorization error: %s", error->message); + return FALSE; + } + + authorized = polkit_authorization_result_get_is_authorized (result); + } if (!authorized) { @@ -256,6 +347,7 @@ on_bus_acquired (GDBusConnection *connection, G_DBUS_INTERFACE_SKELETON_FLAGS_HANDLE_METHOD_INVOCATIONS_IN_THREAD); g_signal_connect (helper, "handle-deploy", G_CALLBACK (handle_deploy), NULL); + g_signal_connect (helper, "handle-deploy-appstream", G_CALLBACK (handle_deploy_appstream), NULL); g_signal_connect (helper, "g-authorize-method", G_CALLBACK (flatpak_authorize_method_handler), diff --git a/system-helper/org.freedesktop.Flatpak.policy.in b/system-helper/org.freedesktop.Flatpak.policy.in index a420339..a0a1bcc 100644 --- a/system-helper/org.freedesktop.Flatpak.policy.in +++ b/system-helper/org.freedesktop.Flatpak.policy.in @@ -83,4 +83,22 @@ </defaults> </action> + <action id="org.freedesktop.Flatpak.appstream-update"> + <!-- SECURITY: + - Normal users do not require admin authentication to update + appstream data as it will be signed, and the action is required + to update the system when unattended. + - Changing this to anything other than 'yes' will break unattended + updates. + --> + <_description>Update appstream</_description> + <_message>Authentication is required to update software</_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> + </policyconfig> |