diff --git a/data/tests/firmware-base-uri.conf b/data/tests/firmware-base-uri.conf new file mode 100644 index 000000000..d94ac8202 --- /dev/null +++ b/data/tests/firmware-base-uri.conf @@ -0,0 +1,6 @@ +[fwupd Remote] +Enabled=true +Type=download +Keyring=gpg +MetadataURI=https://s3.amazonaws.com/lvfsbucket/downloads/firmware.xml.gz +FirmwareBaseURI=https://my.fancy.cdn/ diff --git a/libfwupd/fwupd-remote.c b/libfwupd/fwupd-remote.c index f935a7dc1..b493f218d 100644 --- a/libfwupd/fwupd-remote.c +++ b/libfwupd/fwupd-remote.c @@ -32,7 +32,9 @@ struct _FwupdRemote FwupdRemoteKind kind; FwupdKeyringKind keyring_kind; gchar *id; + gchar *firmware_base_uri; gchar *metadata_uri; + gchar *metadata_uri_sig; gchar *username; gchar *password; gchar *filename; @@ -135,13 +137,20 @@ fwupd_remote_set_metadata_uri (FwupdRemote *self, const gchar *metadata_uri) /* generate the signature URI too */ suffix = fwupd_remote_get_suffix_for_keyring_kind (self->keyring_kind); if (suffix != NULL) { - g_autofree gchar *url_asc = g_strconcat (metadata_uri, suffix, NULL); - self->uri_asc = fwupd_remote_build_uri (self, url_asc, NULL); + self->metadata_uri_sig = g_strconcat (metadata_uri, suffix, NULL); + self->uri_asc = fwupd_remote_build_uri (self, self->metadata_uri_sig, NULL); basename_asc = g_path_get_basename (soup_uri_get_path (self->uri_asc)); self->filename_asc = g_strdup_printf ("%s-%s", self->id, basename_asc); } } +/* note, this has to be set after MetadataURI */ +static void +fwupd_remote_set_firmware_base_uri (FwupdRemote *self, const gchar *firmware_base_uri) +{ + self->firmware_base_uri = g_strdup (firmware_base_uri); +} + /** * fwupd_remote_kind_from_string: * @kind: a string, e.g. "download" @@ -222,6 +231,7 @@ fwupd_remote_load_from_filename (FwupdRemote *self, GError **error) { const gchar *group = "fwupd Remote"; + g_autofree gchar *firmware_base_uri = NULL; g_autofree gchar *id = NULL; g_autofree gchar *keyring_kind = NULL; g_autofree gchar *metadata_uri = NULL; @@ -326,6 +336,11 @@ fwupd_remote_load_from_filename (FwupdRemote *self, fwupd_remote_set_filename_cache (self, filename_cache); } + /* the base URI is optional */ + firmware_base_uri = g_key_file_get_string (kf, group, "FirmwareBaseURI", NULL); + if (firmware_base_uri != NULL) + fwupd_remote_set_firmware_base_uri (self, firmware_base_uri); + /* dep logic */ order_before = g_key_file_get_string (kf, group, "OrderBefore", NULL); if (order_before != NULL) @@ -510,7 +525,8 @@ fwupd_remote_get_filename_asc (FwupdRemote *self) * @url: the URL to use * @error: the #GError, or %NULL * - * Builds a URI for the URL using the username and password set for the remote. + * Builds a URI for the URL using the username and password set for the remote, + * including any basename URI substitution. * * Returns: (transfer full): a #SoupURI, or %NULL for error * @@ -525,14 +541,38 @@ fwupd_remote_build_uri (FwupdRemote *self, const gchar *url, GError **error) g_return_val_if_fail (url != NULL, NULL); g_return_val_if_fail (error == NULL || *error == NULL, NULL); - /* create URI */ - uri = soup_uri_new (url); - if (uri == NULL) { - g_set_error (error, - FWUPD_ERROR, - FWUPD_ERROR_INVALID_FILE, - "Failed to parse URI '%s'", url); - return NULL; + /* create URI, substituting if required */ + if (self->firmware_base_uri != NULL) { + g_autoptr(SoupURI) uri_tmp = NULL; + g_autofree gchar *basename = NULL; + g_autofree gchar *url2 = NULL; + uri_tmp = soup_uri_new (url); + if (uri_tmp == NULL) { + g_set_error (error, + FWUPD_ERROR, + FWUPD_ERROR_INVALID_FILE, + "Failed to parse URI '%s'", url); + return NULL; + } + basename = g_path_get_basename (soup_uri_get_path (uri_tmp)); + url2 = g_build_filename (self->firmware_base_uri, basename, NULL); + uri = soup_uri_new (url2); + if (uri == NULL) { + g_set_error (error, + FWUPD_ERROR, + FWUPD_ERROR_INVALID_FILE, + "Failed to parse URI '%s'", url2); + return NULL; + } + } else { + uri = soup_uri_new (url); + if (uri == NULL) { + g_set_error (error, + FWUPD_ERROR, + FWUPD_ERROR_INVALID_FILE, + "Failed to parse URI '%s'", url); + return NULL; + } } /* set the username and password from the metadata URI */ @@ -543,6 +583,28 @@ fwupd_remote_build_uri (FwupdRemote *self, const gchar *url, GError **error) return uri; } +/** + * fwupd_remote_build_firmware_uri: + * @self: A #FwupdRemote + * @url: the URL to use + * @error: the #GError, or %NULL + * + * Builds a URI for the URL using the username and password set for the remote, + * including any basename URI substitution. + * + * Returns: (transfer full): a URI, or %NULL for error + * + * Since: 0.9.7 + **/ +gchar * +fwupd_remote_build_firmware_uri (FwupdRemote *self, const gchar *url, GError **error) +{ + g_autoptr(SoupURI) uri = fwupd_remote_build_uri (self, url, error); + if (uri == NULL) + return NULL; + return soup_uri_to_string (uri, FALSE); +} + /** * fwupd_remote_get_uri: * @self: A #FwupdRemote @@ -577,6 +639,57 @@ fwupd_remote_get_uri_asc (FwupdRemote *self) return self->uri_asc; } +/** + * fwupd_remote_get_metadata_uri: + * @self: A #FwupdRemote + * + * Gets the URI for the remote metadata. + * + * Returns: (transfer none): a URI, or %NULL for invalid. + * + * Since: 0.9.7 + **/ +const gchar * +fwupd_remote_get_metadata_uri (FwupdRemote *self) +{ + g_return_val_if_fail (FWUPD_IS_REMOTE (self), NULL); + return self->metadata_uri; +} + +/** + * fwupd_remote_get_metadata_uri_sig: + * @self: A #FwupdRemote + * + * Gets the URI for the remote metadata signature. + * + * Returns: (transfer none): a URI, or %NULL for invalid. + * + * Since: 0.9.7 + **/ +const gchar * +fwupd_remote_get_metadata_uri_sig (FwupdRemote *self) +{ + g_return_val_if_fail (FWUPD_IS_REMOTE (self), NULL); + return self->metadata_uri_sig; +} + +/** + * fwupd_remote_get_firmware_base_uri: + * @self: A #FwupdRemote + * + * Gets the base URI for firmware. + * + * Returns: (transfer none): a URI, or %NULL for unset. + * + * Since: 0.9.7 + **/ +const gchar * +fwupd_remote_get_firmware_base_uri (FwupdRemote *self) +{ + g_return_val_if_fail (FWUPD_IS_REMOTE (self), NULL); + return self->firmware_base_uri; +} + /** * fwupd_remote_get_enabled: * @self: A #FwupdRemote @@ -630,6 +743,10 @@ fwupd_remote_to_variant_builder (FwupdRemote *self, GVariantBuilder *builder) g_variant_builder_add (builder, "{sv}", "Url", g_variant_new_string (self->metadata_uri)); } + if (self->firmware_base_uri != NULL) { + g_variant_builder_add (builder, "{sv}", "FirmwareBaseUri", + g_variant_new_string (self->firmware_base_uri)); + } if (self->priority != 0) { g_variant_builder_add (builder, "{sv}", "Priority", g_variant_new_int32 (self->priority)); @@ -688,6 +805,8 @@ fwupd_remote_set_from_variant_iter (FwupdRemote *self, GVariantIter *iter) self->priority = g_variant_get_int32 (value); } else if (g_strcmp0 (key, "ModificationTime") == 0) { self->mtime = g_variant_get_uint64 (value); + } else if (g_strcmp0 (key, "FirmwareBaseUri") == 0) { + fwupd_remote_set_firmware_base_uri (self, g_variant_get_string (value, NULL)); } } } @@ -805,6 +924,7 @@ fwupd_remote_finalize (GObject *obj) g_free (self->id); g_free (self->metadata_uri); + g_free (self->firmware_base_uri); g_free (self->username); g_free (self->password); g_free (self->filename); diff --git a/libfwupd/fwupd-remote.h b/libfwupd/fwupd-remote.h index b2ea55e56..2f7171770 100644 --- a/libfwupd/fwupd-remote.h +++ b/libfwupd/fwupd-remote.h @@ -50,17 +50,27 @@ const gchar *fwupd_remote_get_username (FwupdRemote *self); const gchar *fwupd_remote_get_password (FwupdRemote *self); const gchar *fwupd_remote_get_filename_cache (FwupdRemote *self); const gchar *fwupd_remote_get_filename_cache_sig (FwupdRemote *self); +const gchar *fwupd_remote_get_firmware_base_uri (FwupdRemote *self); +const gchar *fwupd_remote_get_metadata_uri (FwupdRemote *self); +const gchar *fwupd_remote_get_metadata_uri_sig (FwupdRemote *self); gboolean fwupd_remote_get_enabled (FwupdRemote *self); gint fwupd_remote_get_priority (FwupdRemote *self); guint64 fwupd_remote_get_age (FwupdRemote *self); FwupdRemoteKind fwupd_remote_get_kind (FwupdRemote *self); FwupdKeyringKind fwupd_remote_get_keyring_kind (FwupdRemote *self); -SoupURI *fwupd_remote_get_uri (FwupdRemote *self); -SoupURI *fwupd_remote_get_uri_asc (FwupdRemote *self); +gchar *fwupd_remote_build_firmware_uri (FwupdRemote *self, + const gchar *url, + GError **error); SoupURI *fwupd_remote_build_uri (FwupdRemote *self, const gchar *url, GError **error); +/* deprecated */ +SoupURI *fwupd_remote_get_uri (FwupdRemote *self) +G_DEPRECATED_FOR(fwupd_remote_get_metadata_uri); +SoupURI *fwupd_remote_get_uri_asc (FwupdRemote *self) +G_DEPRECATED_FOR(fwupd_remote_get_metadata_uri_sig); + G_END_DECLS #endif /* __FWUPD_REMOTE_H */ diff --git a/libfwupd/fwupd-self-test.c b/libfwupd/fwupd-self-test.c index a8f21eb7b..e581ccb10 100644 --- a/libfwupd/fwupd-self-test.c +++ b/libfwupd/fwupd-self-test.c @@ -111,8 +111,8 @@ fwupd_remote_download_func (void) g_assert_cmpint (fwupd_remote_get_keyring_kind (remote), ==, FWUPD_KEYRING_KIND_GPG); g_assert_cmpint (fwupd_remote_get_priority (remote), ==, 0); g_assert (fwupd_remote_get_enabled (remote)); - g_assert (fwupd_remote_get_uri (remote) != NULL); - g_assert (fwupd_remote_get_uri_asc (remote) != NULL); + g_assert (fwupd_remote_get_metadata_uri (remote) != NULL); + g_assert (fwupd_remote_get_metadata_uri_sig (remote) != NULL); g_assert_cmpstr (fwupd_remote_get_filename (remote), ==, "lvfs-firmware.xml.gz"); g_assert_cmpstr (fwupd_remote_get_filename_asc (remote), ==, "lvfs-firmware.xml.gz.asc"); g_assert_cmpstr (fwupd_remote_get_filename_cache (remote), ==, @@ -121,6 +121,34 @@ fwupd_remote_download_func (void) LOCALSTATEDIR "/lib/fwupd/remotes.d/lvfs/metadata.xml.gz.asc"); } +/* verify we used the FirmwareBaseURI just for firmware */ +static void +fwupd_remote_baseuri_func (void) +{ + gboolean ret; + g_autofree gchar *firmware_uri = NULL; + g_autofree gchar *fn = NULL; + g_autoptr(FwupdRemote) remote = NULL; + g_autoptr(GError) error = NULL; + + remote = fwupd_remote_new (); + fn = g_build_filename (TESTDATADIR, "tests", "firmware-base-uri.conf", NULL); + ret = fwupd_remote_load_from_filename (remote, fn, NULL, &error); + g_assert_no_error (error); + g_assert (ret); + g_assert_cmpint (fwupd_remote_get_kind (remote), ==, FWUPD_REMOTE_KIND_DOWNLOAD); + g_assert_cmpint (fwupd_remote_get_keyring_kind (remote), ==, FWUPD_KEYRING_KIND_GPG); + g_assert_cmpint (fwupd_remote_get_priority (remote), ==, 0); + g_assert (fwupd_remote_get_enabled (remote)); + g_assert_cmpstr (fwupd_remote_get_metadata_uri (remote), ==, + "https://s3.amazonaws.com/lvfsbucket/downloads/firmware.xml.gz"); + g_assert_cmpstr (fwupd_remote_get_metadata_uri_sig (remote), ==, + "https://s3.amazonaws.com/lvfsbucket/downloads/firmware.xml.gz.asc"); + firmware_uri = fwupd_remote_build_firmware_uri (remote, "http://bbc.co.uk/firmware.cab", &error); + g_assert_no_error (error); + g_assert_cmpstr (firmware_uri, ==, "https://my.fancy.cdn/firmware.cab"); +} + static void fwupd_remote_local_func (void) { @@ -137,8 +165,8 @@ fwupd_remote_local_func (void) g_assert_cmpint (fwupd_remote_get_kind (remote), ==, FWUPD_REMOTE_KIND_LOCAL); g_assert_cmpint (fwupd_remote_get_keyring_kind (remote), ==, FWUPD_KEYRING_KIND_NONE); g_assert (fwupd_remote_get_enabled (remote)); - g_assert (fwupd_remote_get_uri (remote) == NULL); - g_assert (fwupd_remote_get_uri_asc (remote) == NULL); + g_assert (fwupd_remote_get_metadata_uri (remote) == NULL); + g_assert (fwupd_remote_get_metadata_uri_sig (remote) == NULL); g_assert_cmpstr (fwupd_remote_get_filename (remote), ==, NULL); g_assert_cmpstr (fwupd_remote_get_filename_asc (remote), ==, NULL); g_assert_cmpstr (fwupd_remote_get_filename_cache (remote), ==, "@datadir@/fwupd/remotes.d/fwupd/metadata.xml"); @@ -256,7 +284,7 @@ fwupd_client_remotes_func (void) g_assert (remote2 != NULL); g_assert_cmpstr (fwupd_remote_get_id (remote2), ==, "lvfs"); g_assert (fwupd_remote_get_enabled (remote2)); - g_assert (fwupd_remote_get_uri (remote2) != NULL); + g_assert (fwupd_remote_get_metadata_uri (remote2) != NULL); /* check we set an error when unfound */ remote3 = fwupd_client_get_remote_by_id (client, "XXXX", NULL, &error); @@ -317,6 +345,7 @@ main (int argc, char **argv) g_test_add_func ("/fwupd/enums", fwupd_enums_func); g_test_add_func ("/fwupd/result", fwupd_result_func); g_test_add_func ("/fwupd/remote{download}", fwupd_remote_download_func); + g_test_add_func ("/fwupd/remote{base-uri}", fwupd_remote_baseuri_func); g_test_add_func ("/fwupd/remote{local}", fwupd_remote_local_func); if (fwupd_has_system_bus ()) { g_test_add_func ("/fwupd/client{remotes}", fwupd_client_remotes_func); diff --git a/libfwupd/meson.build b/libfwupd/meson.build index 73b226565..672b33e13 100644 --- a/libfwupd/meson.build +++ b/libfwupd/meson.build @@ -122,6 +122,7 @@ if get_option('enable-tests') c_args : [ cargs, '-DLOCALSTATEDIR="' + localstatedir + '"', + '-DTESTDATADIR="' + testdatadir + '"', '-DFU_SELF_TEST_REMOTES_DIR="' + testdatadir + '"', ], ) diff --git a/src/fu-engine.c b/src/fu-engine.c index d3f4e677b..1704195a0 100644 --- a/src/fu-engine.c +++ b/src/fu-engine.c @@ -229,11 +229,25 @@ fu_engine_get_sysconfig_dir (void) } static void -fu_engine_set_release_from_item (FwupdRelease *rel, AsRelease *release) +fu_engine_set_release_from_appstream (FuEngine *self, FwupdRelease *rel, + AsApp *app, AsRelease *release) { AsChecksum *csum; + FwupdRemote *remote = NULL; + const gchar *remote_id; const gchar *tmp; + /* find the remote */ + remote_id = as_app_get_metadata_item (app, "fwupd::RemoteID"); + if (remote_id != NULL) { + remote = fu_config_get_remote_by_id (self->config, remote_id); + if (remote == NULL) + g_warning ("failed to find remote %s", remote_id); + } else { + g_warning ("no fwupd::RemoteID set on %s", + as_app_get_unique_id (app)); + } + tmp = as_release_get_version (release); if (tmp != NULL) fwupd_release_set_version (rel, tmp); @@ -241,8 +255,14 @@ fu_engine_set_release_from_item (FwupdRelease *rel, AsRelease *release) if (tmp != NULL) fwupd_release_set_description (rel, tmp); tmp = as_release_get_location_default (release); - if (tmp != NULL) - fwupd_release_set_uri (rel, tmp); + if (tmp != NULL) { + g_autofree gchar *uri = NULL; + if (remote != NULL) + uri = fwupd_remote_build_firmware_uri (remote, tmp, NULL); + if (uri == NULL) + uri = g_strdup (tmp); + fwupd_release_set_uri (rel, uri); + } csum = as_release_get_checksum_by_target (release, AS_CHECKSUM_TARGET_CONTENT); if (csum != NULL) { tmp = as_checksum_get_filename (csum); @@ -1681,7 +1701,9 @@ fu_engine_get_updates_item_update (FuEngine *self, FuDeviceItem *item) fu_device_set_unique_id (item->device, tmp); /* add release information */ - fu_engine_set_release_from_item (fwupd_result_get_release (FWUPD_RESULT (item->device)), release); + fu_engine_set_release_from_appstream (self, + fwupd_result_get_release (FWUPD_RESULT (item->device)), + app, release); /* get the list of releases newer than the one installed */ updates_list = g_ptr_array_new (); @@ -1833,7 +1855,7 @@ fu_engine_get_result_from_app (FuEngine *self, AsApp *app, GError **error) fwupd_release_set_vendor (rel, as_app_get_developer_name (app, NULL)); fwupd_result_set_unique_id (res, as_app_get_unique_id (app)); fwupd_release_set_appstream_id (rel, as_app_get_id (app)); - fu_engine_set_release_from_item (rel, release); + fu_engine_set_release_from_appstream (self, rel, app, release); return g_steal_pointer (&res); } @@ -2032,7 +2054,7 @@ fu_engine_get_releases (FuEngine *self, const gchar *device_id, GError **error) for (guint j = 0; j < releases_tmp->len; j++) { AsRelease *release = g_ptr_array_index (releases_tmp, j); FwupdRelease *rel = fwupd_release_new (); - fu_engine_set_release_from_item (rel, release); + fu_engine_set_release_from_appstream (self, rel, app, release); g_ptr_array_add (releases, g_object_ref (rel)); } } diff --git a/src/fu-util.c b/src/fu-util.c index 5f12a82c1..6427a80ac 100644 --- a/src/fu-util.c +++ b/src/fu-util.c @@ -782,20 +782,22 @@ fu_util_download_metadata_for_remote (FuUtilPrivate *priv, g_autofree gchar *cache_dir = NULL; g_autofree gchar *filename = NULL; g_autofree gchar *filename_asc = NULL; + g_autoptr(SoupURI) uri = NULL; + g_autoptr(SoupURI) uri_sig = NULL; /* download the metadata */ cache_dir = g_build_filename (g_get_user_cache_dir (), "fwupdmgr", NULL); filename = g_build_filename (cache_dir, fwupd_remote_get_filename (remote), NULL); if (!fu_common_mkdir_parent (filename, error)) return FALSE; - if (!fu_util_download_file (priv, fwupd_remote_get_uri (remote), - filename, NULL, error)) + uri = soup_uri_new (fwupd_remote_get_metadata_uri (remote)); + if (!fu_util_download_file (priv, uri, filename, NULL, error)) return FALSE; /* download the signature */ filename_asc = g_build_filename (cache_dir, fwupd_remote_get_filename_asc (remote), NULL); - if (!fu_util_download_file (priv, fwupd_remote_get_uri_asc (remote), - filename_asc, NULL, error)) + uri_sig = soup_uri_new (fwupd_remote_get_metadata_uri_sig (remote)); + if (!fu_util_download_file (priv, uri_sig, filename_asc, NULL, error)) return FALSE; /* send all this to fwupd */ @@ -1098,7 +1100,6 @@ fu_util_get_remotes (FuUtilPrivate *priv, gchar **values, GError **error) FwupdRemote *remote = g_ptr_array_index (remotes, i); FwupdRemoteKind kind = fwupd_remote_get_kind (remote); FwupdKeyringKind keyring_kind = fwupd_remote_get_keyring_kind (remote); - SoupURI *uri; const gchar *tmp; gint priority; gdouble age; @@ -1184,17 +1185,20 @@ fu_util_get_remotes (FuUtilPrivate *priv, gchar **values, GError **error) /* TRANSLATORS: locatation of the local file */ fu_util_print_data (_("Location Signature"), tmp); } - uri = fwupd_remote_get_uri (remote); - if (uri != NULL) { - g_autofree gchar *uri_str = soup_uri_to_string (uri, FALSE); + tmp = fwupd_remote_get_metadata_uri (remote); + if (tmp != NULL) { /* TRANSLATORS: remote URI */ - fu_util_print_data (_("Metadata URI"), uri_str); + fu_util_print_data (_("Metadata URI"), tmp); } - uri = fwupd_remote_get_uri_asc (remote); - if (uri != NULL) { - g_autofree gchar *uri_str = soup_uri_to_string (uri, FALSE); + tmp = fwupd_remote_get_metadata_uri_sig (remote); + if (tmp != NULL) { /* TRANSLATORS: remote URI */ - fu_util_print_data (_("Metadata URI Signature"), uri_str); + fu_util_print_data (_("Metadata URI Signature"), tmp); + } + tmp = fwupd_remote_get_firmware_base_uri (remote); + if (tmp != NULL) { + /* TRANSLATORS: remote URI */ + fu_util_print_data (_("Firmware Base URI"), tmp); } /* newline */