diff --git a/app/flatpak-builtins-add-remote.c b/app/flatpak-builtins-add-remote.c index f1b6f7b9..8a7afaf1 100644 --- a/app/flatpak-builtins-add-remote.c +++ b/app/flatpak-builtins-add-remote.c @@ -36,13 +36,6 @@ #include "flatpak-utils.h" #include "flatpak-chain-input-stream.h" -#define FLATPAK_REPO_GROUP "Flatpak Repo" -#define FLATPAK_REPO_URL_KEY "Url" -#define FLATPAK_REPO_TITLE_KEY "Title" -#define FLATPAK_REPO_DEFAULT_BRANCH_KEY "DefaultBranch" -#define FLATPAK_REPO_GPGKEY_KEY "GPGKey" -#define FLATPAK_REPO_NODEPS_KEY "NoDeps" - static gboolean opt_no_gpg_verify; static gboolean opt_do_gpg_verify; static gboolean opt_do_enumerate; diff --git a/app/flatpak-builtins-install.c b/app/flatpak-builtins-install.c index 744a9f0e..81426dca 100644 --- a/app/flatpak-builtins-install.c +++ b/app/flatpak-builtins-install.c @@ -144,6 +144,96 @@ install_bundle (FlatpakDir *dir, return TRUE; } +static gboolean +handle_runtime_repo_deps (FlatpakDir *dir, GBytes *data, GError **error) +{ + g_autoptr(GKeyFile) keyfile = g_key_file_new (); + g_autoptr(GKeyFile) dep_keyfile = g_key_file_new (); + g_autofree char *dep_url = NULL; + g_autoptr(GBytes) dep_data = NULL; + g_autofree char *runtime_url = NULL; + g_autofree char *old_remote = NULL; + g_autofree char *new_remote = NULL; + g_autofree char *basename = NULL; + g_autoptr(SoupURI) uri = NULL; + g_auto(GStrv) remotes = NULL; + g_autoptr(GKeyFile) config = NULL; + g_autoptr(GBytes) gpg_key = NULL; + g_autofree char *group = NULL; + char *t; + int i; + + if (!g_key_file_load_from_data (keyfile, g_bytes_get_data (data, NULL), g_bytes_get_size (data), + 0, error)) + return FALSE; + + dep_url = g_key_file_get_string (keyfile, FLATPAK_REF_GROUP, + FLATPAK_REF_RUNTIME_REPO_KEY, NULL); + if (dep_url == NULL) + return TRUE; + + dep_data = download_uri (dep_url, error); + if (dep_data == NULL) + { + g_prefix_error (error, "Can't load dependent file %s", dep_url); + return FALSE; + } + + uri = soup_uri_new (dep_url); + basename = g_path_get_basename (soup_uri_get_path (uri)); + /* Strip suffix */ + t = strchr (basename, '.'); + if (t != NULL) + *t = 0; + + /* Find a free remote name */ + remotes = flatpak_dir_list_remotes (dir, NULL, NULL); + i = 0; + do + { + g_clear_pointer (&new_remote, g_free); + + if (i == 0) + new_remote = g_strdup (basename); + else + new_remote = g_strdup_printf ("%s-%d", basename, i); + i++; + } + while (remotes != NULL && g_strv_contains ((const char * const*)remotes, new_remote)); + + config = flatpak_dir_parse_repofile (dir, new_remote, dep_data, &gpg_key, NULL, error); + if (config == NULL) + { + g_prefix_error (error, "Can't parse dependent file %s", dep_url); + return FALSE; + } + + /* See if it already exists */ + group = g_strdup_printf ("remote \"%s\"", new_remote); + runtime_url = g_key_file_get_string (config, group, "url", NULL); + g_assert (runtime_url != NULL); + + old_remote = flatpak_dir_find_remote_by_uri (dir, runtime_url); + if (old_remote == NULL && flatpak_dir_is_user (dir)) + { + g_autoptr(FlatpakDir) system_dir = flatpak_dir_get_system (); + old_remote = flatpak_dir_find_remote_by_uri (system_dir, runtime_url); + } + + if (old_remote != NULL) + return TRUE; + + if (flatpak_yes_no_prompt (_("This application depends on runtimes from:\n %s\nConfigure this as new remote '%s'"), + runtime_url, new_remote)) + { + if (!flatpak_dir_modify_remote (dir, new_remote, config, gpg_key, NULL, error)) + return FALSE; + if (!flatpak_dir_recreate_repo (dir, NULL, error)) + return FALSE; + } + + return TRUE; +} static gboolean install_from (FlatpakDir *dir, @@ -194,6 +284,9 @@ install_from (FlatpakDir *dir, file_data = g_bytes_new_take (g_steal_pointer (&data), data_len); } + if (!handle_runtime_repo_deps (dir, file_data, error)) + return FALSE; + if (!flatpak_dir_create_remote_for_ref_file (dir, file_data, &remote, &ref, error)) return FALSE; diff --git a/common/flatpak-dir.c b/common/flatpak-dir.c index c09f2e5e..9a843134 100644 --- a/common/flatpak-dir.c +++ b/common/flatpak-dir.c @@ -897,6 +897,16 @@ flatpak_dir_ensure_path (FlatpakDir *self, return flatpak_mkdir_p (self->basedir, cancellable, error); } +/* Warning: This is not threadsafe, don't use in libflatpak */ +gboolean +flatpak_dir_recreate_repo (FlatpakDir *self, + GCancellable *cancellable, + GError **error) +{ + g_autoptr(OstreeRepo) old_repo = g_steal_pointer (&self->repo); + return flatpak_dir_ensure_repo (self, cancellable, error); +} + gboolean flatpak_dir_ensure_repo (FlatpakDir *self, GCancellable *cancellable, @@ -5643,6 +5653,91 @@ flatpak_dir_create_origin_remote (FlatpakDir *self, return g_steal_pointer (&remote); } +GKeyFile * +flatpak_dir_parse_repofile (FlatpakDir *self, + const char *remote_name, + GBytes *data, + GBytes **gpg_data_out, + GCancellable *cancellable, + GError **error) +{ + g_autoptr(GKeyFile) keyfile = g_key_file_new (); + g_autofree char *remote = NULL; + g_autoptr(GError) local_error = NULL; + g_autoptr(GBytes) gpg_data = NULL; + g_autofree char *uri = NULL; + g_autofree char *title = NULL; + g_autofree char *gpg_key = NULL; + g_autofree char *default_branch = NULL; + gboolean nodeps; + GKeyFile *config = g_key_file_new (); + g_autofree char *group = g_strdup_printf ("remote \"%s\"", remote_name); + + if (!g_key_file_load_from_data (keyfile, + g_bytes_get_data (data, NULL), + g_bytes_get_size (data), + 0, &local_error)) + { + flatpak_fail (error, "Invalid .flatpakref: %s\n", local_error->message); + return NULL; + } + + if (!g_key_file_has_group (keyfile, FLATPAK_REPO_GROUP)) + { + flatpak_fail (error, "Invalid .flatpakref\n"); + return NULL; + } + + uri = g_key_file_get_string (keyfile, FLATPAK_REPO_GROUP, + FLATPAK_REPO_URL_KEY, NULL); + if (uri == NULL) + { + flatpak_fail (error, "Invalid .flatpakref\n"); + return NULL; + } + + g_key_file_set_string (config, group, "url", uri); + + title = g_key_file_get_locale_string (keyfile, FLATPAK_REPO_GROUP, + FLATPAK_REPO_TITLE_KEY, NULL, NULL); + if (title != NULL) + g_key_file_set_string (config, group, "xa.title", title); + + default_branch = g_key_file_get_locale_string (keyfile, FLATPAK_REPO_GROUP, + FLATPAK_REPO_DEFAULT_BRANCH_KEY, NULL, NULL); + if (default_branch != NULL) + g_key_file_set_string (config, group, "xa.default-branch", default_branch); + + nodeps = g_key_file_get_boolean (keyfile, FLATPAK_REPO_GROUP, + FLATPAK_REPO_NODEPS_KEY, NULL); + if (nodeps) + g_key_file_set_boolean (config, group, "xa.nodeps", TRUE); + + gpg_key = g_key_file_get_string (keyfile, FLATPAK_REPO_GROUP, + FLATPAK_REPO_GPGKEY_KEY, NULL); + if (gpg_key != NULL) + { + guchar *decoded; + gsize decoded_len; + + gpg_key = g_strstrip (gpg_key); + decoded = g_base64_decode (gpg_key, &decoded_len); + if (decoded_len < 10) /* Check some minimal size so we don't get crap */ + { + flatpak_fail (error, "Invalid gpg key\n"); + return NULL; + } + + gpg_data = g_bytes_new_take (decoded, decoded_len); + g_key_file_set_boolean (config, group, "gpg-verify", TRUE); + g_key_file_set_boolean (config, group, "gpg-verify-summary", TRUE); + } + + *gpg_data_out = g_steal_pointer (&gpg_data); + + return g_steal_pointer (&config); +} + static gboolean parse_ref_file (GBytes *data, char **name_out, diff --git a/common/flatpak-dir.h b/common/flatpak-dir.h index e663de31..745f4ea4 100644 --- a/common/flatpak-dir.h +++ b/common/flatpak-dir.h @@ -39,12 +39,20 @@ GType flatpak_deploy_get_type (void); #define FLATPAK_REF_GROUP "Flatpak Ref" #define FLATPAK_REF_URL_KEY "Url" +#define FLATPAK_REF_RUNTIME_REPO_KEY "RuntimeRepo" #define FLATPAK_REF_TITLE_KEY "Title" #define FLATPAK_REF_GPGKEY_KEY "GPGKey" #define FLATPAK_REF_IS_RUNTIME_KEY "IsRuntime" #define FLATPAK_REF_NAME_KEY "Name" #define FLATPAK_REF_BRANCH_KEY "Branch" +#define FLATPAK_REPO_GROUP "Flatpak Repo" +#define FLATPAK_REPO_URL_KEY "Url" +#define FLATPAK_REPO_TITLE_KEY "Title" +#define FLATPAK_REPO_DEFAULT_BRANCH_KEY "DefaultBranch" +#define FLATPAK_REPO_GPGKEY_KEY "GPGKey" +#define FLATPAK_REPO_NODEPS_KEY "NoDeps" + typedef struct { char *ref; @@ -223,6 +231,9 @@ gboolean flatpak_dir_ensure_path (FlatpakDir *self, gboolean flatpak_dir_use_child_repo (FlatpakDir *self); gboolean flatpak_dir_ensure_system_child_repo (FlatpakDir *self, GError **error); +gboolean flatpak_dir_recreate_repo (FlatpakDir *self, + GCancellable *cancellable, + GError **error); gboolean flatpak_dir_ensure_repo (FlatpakDir *self, GCancellable *cancellable, GError **error); @@ -423,6 +434,12 @@ gboolean flatpak_dir_create_remote_for_ref_file (FlatpakDir *self, char **remote_name_out, char **ref_out, GError **error); +GKeyFile * flatpak_dir_parse_repofile (FlatpakDir *self, + const char *remote_name, + GBytes *data, + GBytes **gpg_data_out, + GCancellable *cancellable, + GError **error); char *flatpak_dir_find_remote_by_uri (FlatpakDir *self, const char *uri);