diff options
author | Richard Hughes <richard@hughsie.com> | 2015-11-15 10:34:44 +0000 |
---|---|---|
committer | Richard Hughes <richard@hughsie.com> | 2015-11-15 10:39:19 +0000 |
commit | 98ed5eba8d32907e7da36f29c266d3d77b28feff (patch) | |
tree | cc6ef45c0a37a5ea714c1be74d474644db660b65 | |
parent | bc645ec63525248a974a5c31cd6167cd77d34c4f (diff) | |
download | appstream-glib-98ed5eba8d32907e7da36f29c266d3d77b28feff.tar.gz |
Generate GUID values according to RFC4122
Also, add a 'generate-guid' command to appstream-util.
-rw-r--r-- | client/as-util.c | 27 | ||||
-rw-r--r-- | configure.ac | 1 | ||||
-rw-r--r-- | contrib/libappstream-glib.spec.in | 1 | ||||
-rw-r--r-- | libappstream-glib/Makefile.am | 3 | ||||
-rw-r--r-- | libappstream-glib/appstream-glib.pc.in | 2 | ||||
-rw-r--r-- | libappstream-glib/as-self-test.c | 9 | ||||
-rw-r--r-- | libappstream-glib/as-utils.c | 89 |
7 files changed, 87 insertions, 45 deletions
diff --git a/client/as-util.c b/client/as-util.c index b156109..19f9c72 100644 --- a/client/as-util.c +++ b/client/as-util.c @@ -3436,6 +3436,27 @@ as_util_pad_strings (const gchar *id, const gchar *msg, guint align) } /** + * as_util_generate_guid: + **/ +static gboolean +as_util_generate_guid (AsUtilPrivate *priv, gchar **values, GError **error) +{ + g_autofree gchar *guid = NULL; + + /* check args */ + if (g_strv_length (values) != 1) { + g_set_error_literal (error, + AS_ERROR, + AS_ERROR_INVALID_ARGUMENTS, + "Not enough arguments, expected STRING"); + return FALSE; + } + guid = as_utils_guid_from_string (values[0]); + g_print ("%s\n", guid); + return TRUE; +} + +/** * as_util_compare: **/ static gboolean @@ -3884,6 +3905,12 @@ main (int argc, char *argv[]) /* TRANSLATORS: command description */ _("Compare the contents of two AppStream files"), as_util_compare); + as_util_add (priv->cmd_array, + "generate-guid", + NULL, + /* TRANSLATORS: command description */ + _("Generate a GUID from an input string"), + as_util_generate_guid); /* sort by command name */ g_ptr_array_sort (priv->cmd_array, diff --git a/configure.ac b/configure.ac index 9cecfd2..0385b2c 100644 --- a/configure.ac +++ b/configure.ac @@ -128,6 +128,7 @@ fi AM_CONDITIONAL(HAVE_GPERF, [test x$GPERF != xno]) PKG_CHECK_MODULES(GLIB, glib-2.0 >= 2.45.8 gio-2.0 gobject-2.0 gthread-2.0 gio-unix-2.0 gmodule-2.0) +PKG_CHECK_MODULES(UUID, uuid) PKG_CHECK_MODULES(LIBARCHIVE, libarchive) PKG_CHECK_MODULES(SOUP, libsoup-2.4 >= 2.51.92) PKG_CHECK_MODULES(GDKPIXBUF, gdk-pixbuf-2.0 >= 2.31.5) diff --git a/contrib/libappstream-glib.spec.in b/contrib/libappstream-glib.spec.in index b7e7ecd..6ce5b13 100644 --- a/contrib/libappstream-glib.spec.in +++ b/contrib/libappstream-glib.spec.in @@ -21,6 +21,7 @@ BuildRequires: gtk3-devel BuildRequires: gettext BuildRequires: intltool BuildRequires: libgcab1-devel +BuildRequires: libuuid-devel # for the builder component BuildRequires: fontconfig-devel diff --git a/libappstream-glib/Makefile.am b/libappstream-glib/Makefile.am index 4c9a33e..a0bf163 100644 --- a/libappstream-glib/Makefile.am +++ b/libappstream-glib/Makefile.am @@ -11,6 +11,7 @@ AM_CPPFLAGS = \ $(GDKPIXBUF_CFLAGS) \ $(LIBARCHIVE_CFLAGS) \ $(SOUP_CFLAGS) \ + $(UUID_CFLAGS) \ $(YAML_CFLAGS) \ -I$(top_srcdir)/libappstream-glib \ -I$(top_builddir)/libappstream-glib \ @@ -148,6 +149,7 @@ libappstream_glib_la_LIBADD = \ $(GDKPIXBUF_LIBS) \ $(LIBARCHIVE_LIBS) \ $(SOUP_LIBS) \ + $(UUID_LIBS) \ $(YAML_LIBS) libappstream_glib_la_LDFLAGS = \ @@ -168,6 +170,7 @@ as_self_test_LDADD = \ $(GDKPIXBUF_LIBS) \ $(LIBARCHIVE_LIBS) \ $(SOUP_LIBS) \ + $(UUID_LIBS) \ $(YAML_LIBS) \ $(lib_LTLIBRARIES) as_self_test_CFLAGS = $(WARNINGFLAGS_C) diff --git a/libappstream-glib/appstream-glib.pc.in b/libappstream-glib/appstream-glib.pc.in index caf82ab..ed7ee3b 100644 --- a/libappstream-glib/appstream-glib.pc.in +++ b/libappstream-glib/appstream-glib.pc.in @@ -6,7 +6,7 @@ includedir=@includedir@ Name: appstream-glib Description: Objects and helper methods to help reading and writing AppStream metadata Version: @VERSION@ -Requires.private: libarchive, libgcab-1.0 +Requires.private: libarchive, libgcab-1.0, libuuid Requires: glib-2.0, gobject-2.0, gdk-pixbuf-2.0 Libs: -L${libdir} -lappstream-glib Cflags: -I${includedir}/libappstream-glib diff --git a/libappstream-glib/as-self-test.c b/libappstream-glib/as-self-test.c index 2df61be..5a2a14d 100644 --- a/libappstream-glib/as-self-test.c +++ b/libappstream-glib/as-self-test.c @@ -3336,7 +3336,8 @@ as_test_store_speed_desktop_func (void) static void as_test_utils_guid_func (void) { - g_autofree gchar *guid = NULL; + g_autofree gchar *guid1 = NULL; + g_autofree gchar *guid2 = NULL; /* invalid */ g_assert (!as_utils_guid_is_valid (NULL)); @@ -3349,8 +3350,10 @@ as_test_utils_guid_func (void) g_assert (as_utils_guid_is_valid ("1ff60ab2-3905-06a1-b476-0371f00c9e9b")); /* make valid */ - guid = as_utils_guid_from_string ("0x8086:0x0406"); - g_assert_cmpstr (guid, ==, "1ff60ab2-3905-06a1-b476-0371f00c9e9b"); + guid1 = as_utils_guid_from_string ("python.org"); + g_assert_cmpstr (guid1, ==, "886313e1-3b8a-5372-9b90-0c9aee199e5d"); + guid2 = as_utils_guid_from_string ("8086:0406"); + g_assert_cmpstr (guid2, ==, "1fbd1f2c-80f4-5d7c-a6ad-35c7b9bd5486"); } static void diff --git a/libappstream-glib/as-utils.c b/libappstream-glib/as-utils.c index 730b08e..2ed13cf 100644 --- a/libappstream-glib/as-utils.c +++ b/libappstream-glib/as-utils.c @@ -38,6 +38,7 @@ #include <archive.h> #include <libsoup/soup.h> #include <stdlib.h> +#include <uuid.h> #include "as-app.h" #include "as-enums.h" @@ -1592,20 +1593,6 @@ as_ptr_array_find_string (GPtrArray *array, const gchar *value) } /** - * as_utils_guid_is_xdigit: - **/ -static gboolean -as_utils_guid_is_xdigit (const gchar *str) -{ - guint i; - for (i = 0; str[i] != '\0'; i++) { - if (!g_ascii_isxdigit (str[i])) - return FALSE; - } - return TRUE; -} - -/** * as_utils_guid_is_valid: * @guid: string to check * @@ -1618,32 +1605,28 @@ as_utils_guid_is_xdigit (const gchar *str) gboolean as_utils_guid_is_valid (const gchar *guid) { - g_auto(GStrv) split = NULL; + gint rc; + uuid_t uu; if (guid == NULL) return FALSE; - split = g_strsplit (guid, "-", -1); - if (g_strv_length (split) != 5) - return FALSE; - if (strlen (split[0]) != 8 || !as_utils_guid_is_xdigit (split[0])) - return FALSE; - if (strlen (split[1]) != 4 || !as_utils_guid_is_xdigit (split[1])) - return FALSE; - if (strlen (split[2]) != 4 || !as_utils_guid_is_xdigit (split[2])) - return FALSE; - if (strlen (split[3]) != 4 || !as_utils_guid_is_xdigit (split[3])) - return FALSE; - if (strlen (split[4]) != 12 || !as_utils_guid_is_xdigit (split[4])) - return FALSE; - return TRUE; + rc = uuid_parse (guid, uu); + return rc == 0; } /** * as_utils_guid_from_string: * @str: A source string to use as a key * - * Returns a GUID for a given string. This uses SHA1 and some string - * modification so even small differences in the @str will produce radically - * different GUID return values. + * Returns a GUID for a given string. This uses a hash and so even small + * differences in the @str will produce radically different return values. + * + * The implementation is taken from RFC4122, Section 4.1.3; specifically + * using a type-5 SHA-1 hash with a DNS namespace. + * The same result can be obtained with this simple python program: + * + * #!/usr/bin/python + * import uuid + * print uuid.uuid5(uuid.NAMESPACE_DNS, 'python.org') * * Returns: A new GUID, or %NULL if the string was invalid * @@ -1652,15 +1635,39 @@ as_utils_guid_is_valid (const gchar *guid) gchar * as_utils_guid_from_string (const gchar *str) { - gchar *tmp; - tmp = g_compute_checksum_for_string (G_CHECKSUM_SHA1, str, -1); - tmp[8] = '-'; - tmp[13] = '-'; - tmp[18] = '-'; - tmp[23] = '-'; - tmp[36] = '\0'; - g_assert (as_utils_guid_is_valid (tmp)); - return tmp; + const gchar *namespace_id = "6ba7b810-9dad-11d1-80b4-00c04fd430c8"; + gchar guid_new[37]; /* 36 plus NUL */ + gsize digestlen = 20; + guint8 hash[20]; + gint rc; + uuid_t uu_namespace; + uuid_t uu_new; + g_autoptr(GChecksum) csum = NULL; + + /* invalid */ + if (str == NULL) + return NULL; + + /* convert the namespace to binary */ + rc = uuid_parse (namespace_id, uu_namespace); + g_assert (rc == 0); + + /* hash the namespace and then the string */ + csum = g_checksum_new (G_CHECKSUM_SHA1); + g_checksum_update (csum, (guchar *) uu_namespace, 16); + g_checksum_update (csum, (guchar *) str, strlen(str)); + g_checksum_get_digest (csum, hash, &digestlen); + + /* copy most parts of the hash 1:1 */ + memcpy(uu_new, hash, 16); + + /* set specific bits according to Section 4.1.3 */ + uu_new[6] = (guint8) ((uu_new[6] & 0x0f) | (5 << 4)); + uu_new[8] = (guint8) ((uu_new[8] & 0x3f) | 0x80); + + /* return as a string */ + uuid_unparse (uu_new, guid_new); + return g_strdup (guid_new); } /** |