[Telepathy-commits] [telepathy-gabble/master] Check hash when we receive a caps from a contact

Alban Crequy alban.crequy at collabora.co.uk
Tue Aug 19 10:52:30 PDT 2008


20080507152437-a41c0-9ce1a77b5d372f2fa744a59b5aa74c939f514f5c.gz
---
 src/gabble-connection.c |    5 +-
 src/presence-cache.c    |   91 ++++++++++++++++++++++++++++----
 src/presence.c          |  134 +++++++++++++++++++++++++++++++++++++---------
 src/presence.h          |    4 +-
 4 files changed, 193 insertions(+), 41 deletions(-)

diff --git a/src/gabble-connection.c b/src/gabble-connection.c
index daeac23..e41eaa0 100644
--- a/src/gabble-connection.c
+++ b/src/gabble-connection.c
@@ -1286,7 +1286,7 @@ _gabble_connection_signal_own_presence (GabbleConnection *self, GError **error)
   GString *ext_string = NULL;
   GSList *features, *i;
   GHashTable *bundles;
-  gchar *caps_hash = gabble_presence_get_xep0115_hash (self->self_presence);
+  gchar *caps_hash;
 
   if (presence->status == GABBLE_PRESENCE_HIDDEN)
     {
@@ -1325,6 +1325,7 @@ _gabble_connection_signal_own_presence (GabbleConnection *self, GError **error)
   g_hash_table_destroy (bundles);
 
   /* XEP-0115 version 1.5 uses a verification string in the 'ver' attribute */
+  caps_hash = gabble_presence_compute_xep0115_hash_from_self_presence (self);
   node = lm_message_node_add_child (node, "c", NULL);
   lm_message_node_set_attributes (
     node,
@@ -1530,7 +1531,7 @@ connection_iq_disco_cb (LmMessageHandler *handler,
         }
     }
 
-  caps_hash = gabble_presence_get_xep0115_hash (self->self_presence);
+  caps_hash = gabble_presence_compute_xep0115_hash_from_self_presence (self);
   DEBUG ("caps_hash='%s'", caps_hash);
   if (NULL == node || bundle_found ||
       g_str_equal (suffix, caps_hash))
diff --git a/src/presence-cache.c b/src/presence-cache.c
index b689975..12b600e 100644
--- a/src/presence-cache.c
+++ b/src/presence-cache.c
@@ -89,6 +89,8 @@ struct _DiscoWaiter
   gchar *resource;
   guint serial;
   gboolean disco_requested;
+  const gchar *hash;
+  const gchar *ver;
 };
 
 /**
@@ -98,6 +100,8 @@ static DiscoWaiter *
 disco_waiter_new (TpHandleRepoIface *repo,
                   TpHandle handle,
                   const gchar *resource,
+                  const gchar *hash,
+                  const gchar *ver,
                   guint serial)
 {
   DiscoWaiter *waiter;
@@ -109,6 +113,8 @@ disco_waiter_new (TpHandleRepoIface *repo,
   waiter->repo = repo;
   waiter->handle = handle;
   waiter->resource = g_strdup (resource);
+  waiter->hash = hash;
+  waiter->hash = ver;
   waiter->serial = serial;
 
   DEBUG ("created waiter %p for handle %u with serial %u", waiter, handle,
@@ -155,7 +161,13 @@ disco_waiter_list_get_request_count (GSList *list)
       DiscoWaiter *waiter = (DiscoWaiter *) i->data;
 
       if (waiter->disco_requested)
-        c++;
+        {
+          if (waiter->hash)
+            /* One waiter is enough if the request has a verification string */
+            c += CAPABILITY_BUNDLE_ENOUGH_TRUST;
+          else
+            c++;
+        }
     }
 
   return c;
@@ -612,26 +624,39 @@ _grab_avatar_sha1 (GabblePresenceCache *cache,
 }
 
 static GSList *
-_extract_cap_bundles (LmMessageNode *lm_node)
+_extract_cap_bundles (
+    LmMessageNode *lm_node,
+    const gchar **hash,
+    const gchar **ver)
 {
-  const gchar *node, *ver, *ext;
+  const gchar *node, *ext;
   GSList *uris = NULL;
   LmMessageNode *cap_node;
 
+  *hash = NULL;
+  *ver = NULL;
+
   cap_node = lm_message_node_get_child_with_namespace (lm_node, "c", NS_CAPS);
 
   if (NULL == cap_node)
-    return NULL;
+      return NULL;
+
+  *hash = lm_message_node_get_attribute (cap_node, "hash");
 
   node = lm_message_node_get_attribute (cap_node, "node");
 
   if (NULL == node)
     return NULL;
 
-  ver = lm_message_node_get_attribute (cap_node, "ver");
+  *ver = lm_message_node_get_attribute (cap_node, "ver");
+
+  if (NULL != *ver)
+    uris = g_slist_prepend (uris, g_strdup_printf ("%s#%s", node, *ver));
 
-  if (NULL != ver)
-    uris = g_slist_prepend (uris, g_strdup_printf ("%s#%s", node, ver));
+  /* If there is a hash, the remote contact uses XEP-0115 v1.5 and the 'ext'
+   * attribute MUST be ignored. */
+  if (NULL != *hash)
+    return uris;
 
   ext = lm_message_node_get_attribute (cap_node, "ext");
 
@@ -660,6 +685,7 @@ _caps_disco_cb (GabbleDisco *disco,
                 gpointer user_data)
 {
   GSList *waiters, *i;
+  DiscoWaiter *waiter_self;
   LmMessageNode *child;
   GabblePresenceCache *cache;
   GabblePresenceCachePrivate *priv;
@@ -769,7 +795,45 @@ _caps_disco_cb (GabbleDisco *disco,
       goto OUT;
     }
 
-  trust = capability_info_recvd (cache, node, handle, caps);
+  waiter_self = NULL;
+  for (i = waiters; NULL != i;)
+    {
+      DiscoWaiter *waiter;
+
+      waiter= (DiscoWaiter *) i->data;
+      if (waiter->handle == handle)
+        {
+          waiter_self = waiter;
+          break;
+        }
+    }
+  if (NULL == waiter_self)
+    {
+      DEBUG ("Ignoring non requested disco reply");
+      goto OUT;
+    }
+
+  if (waiter_self->hash != NULL)
+    {
+      const gchar *computed_hash;
+
+      computed_hash =
+          gabble_presence_compute_xep0115_hash_from_lm_node (query_result);
+
+      if (waiter_self->ver != computed_hash)
+        {
+          /* The received reply does not match the */
+          g_warning ("The announced verification string '%s' does not match "
+              "our hash '%s'.", waiter_self->ver, computed_hash);
+          /* TODO: send queries for waiters? */
+          goto OUT;
+        }
+        trust = CAPABILITY_BUNDLE_ENOUGH_TRUST;
+    }
+  else
+    {
+      trust = capability_info_recvd (cache, node, handle, caps);
+    }
 
   for (i = waiters; NULL != i;)
     {
@@ -857,6 +921,8 @@ static void
 _process_caps_uri (GabblePresenceCache *cache,
                    const gchar *from,
                    const gchar *uri,
+                   const gchar *hash,
+                   const gchar *ver,
                    TpHandle handle,
                    const gchar *resource,
                    guint serial)
@@ -921,7 +987,8 @@ _process_caps_uri (GabblePresenceCache *cache,
         }
 
       waiters = (GSList *) value;
-      waiter = disco_waiter_new (contact_repo, handle, resource, serial);
+      waiter = disco_waiter_new (contact_repo, handle, resource,
+          hash, ver, serial);
       waiters = g_slist_prepend (waiters, waiter);
       g_hash_table_insert (priv->disco_pending, key, waiters);
 
@@ -954,6 +1021,7 @@ _process_caps (GabblePresenceCache *cache,
   GabblePresenceCachePrivate *priv;
   GabblePresenceCapabilities old_caps = 0;
   guint serial;
+  const gchar *hash, *ver;
 
   priv = GABBLE_PRESENCE_CACHE_PRIV (cache);
   serial = priv->caps_serial++;
@@ -962,14 +1030,15 @@ _process_caps (GabblePresenceCache *cache,
   if (resource != NULL)
     resource++;
 
-  uris = _extract_cap_bundles (lm_node);
+  uris = _extract_cap_bundles (lm_node, &hash, &ver);
 
   if (presence)
       old_caps = presence->caps;
 
   for (i = uris; NULL != i; i = i->next)
     {
-      _process_caps_uri (cache, from, (gchar *) i->data, handle, resource, serial);
+      _process_caps_uri (cache, from, (gchar *) i->data, hash, ver, handle,
+          resource, serial);
       g_free (i->data);
 
     }
diff --git a/src/presence.c b/src/presence.c
index b2d880b..6f438ab 100644
--- a/src/presence.c
+++ b/src/presence.c
@@ -478,55 +478,135 @@ feature_strcmp (gconstpointer a, gconstpointer b)
   return strcmp (left, right);
 }
 
-/**
- * gabble_presence_get_xep0115_hash:
- * @self: A #GabblePresence
- *
- * Compute the hash as defined by the XEP-0115
- *
- * Returns: the hash. The called must free the returned hash.
- */
-gchar *
-gabble_presence_get_xep0115_hash (GabblePresence *presence)
+static gchar *
+gabble_presence_compute_xep0115_hash (
+    GPtrArray *features,
+    GPtrArray *identities)
 {
-  GSList *features = capabilities_get_features (presence->caps);
-  GPtrArray *features_ns = g_ptr_array_new ();
   GString *s;
   gchar *str;
   gchar sha1[SHA1_HASH_SIZE];
-  GSList *i;
   unsigned int j;
   gchar *encoded;
 
-  for (i = features; NULL != i; i = i->next)
-    {
-      const Feature *feat = (const Feature *) i->data;
-      g_ptr_array_add (features_ns, (gpointer) feat->ns);
-    }
-
-  g_ptr_array_sort (features_ns, feature_strcmp);
+  g_ptr_array_sort (identities, feature_strcmp);
+  g_ptr_array_sort (features, feature_strcmp);
 
   s = g_string_new ("");
 
-  /* Ugly hack. FIXME: Gabble should handle identities.
-   * http://www.xmpp.org/registrar/disco-categories.html */
-  s = g_string_append (s, "client/pc//Telepathy Gabble " VERSION "<");
+  for (j = 0 ; j < identities->len ; j++)
+    {
+      s = g_string_append (s, g_ptr_array_index (identities, j));
+      s = g_string_append (s, "<");
+    }
 
-  for (j = 0 ; j < features_ns->len ; j++)
+  for (j = 0 ; j < features->len ; j++)
     {
-      s = g_string_append (s, g_ptr_array_index (features_ns, j));
+      s = g_string_append (s, g_ptr_array_index (features, j));
       s = g_string_append (s, "<");
     }
 
+  /* FIXME: add XEP-0128 data forms in the hash */
+
   str = g_string_free (s, FALSE);
   DEBUG ("caps string: '%s'\n", str);
   sha1_bin (str, strlen (str), (guchar *) sha1);
   encoded = base64_encode (SHA1_HASH_SIZE, sha1, FALSE);
   DEBUG ("caps base64: '%s'\n", encoded);
 
-  g_slist_free (features);
-
   return encoded;
 }
 
 
+/**
+ *
+ * Compute the hash as defined by the XEP-0115
+ *
+ * Returns: the hash. The called must free the returned hash.
+ */
+gchar *
+gabble_presence_compute_xep0115_hash_from_lm_node (LmMessageNode *node)
+{
+  GPtrArray *features = g_ptr_array_new ();
+  GPtrArray *identities = g_ptr_array_new ();
+  LmMessageNode *child;
+  gchar *str;
+
+  for (child = node->children; NULL != child; child = child->next)
+    {
+      if (g_str_equal (child->name, "identity"))
+        {
+          const gchar *category;
+          const gchar *name;
+          const gchar *type;
+          const gchar *xmllang;
+
+          category = lm_message_node_get_attribute (child, "category");
+          name = lm_message_node_get_attribute (child, "name");
+          type = lm_message_node_get_attribute (child, "type");
+          xmllang = lm_message_node_get_attribute (child, "xml:lang");
+
+          if (NULL == category)
+            continue;
+          if (NULL == name)
+            name = "";
+          if (NULL == type)
+            type = "";
+          if (NULL == xmllang)
+            xmllang = "";
+
+          g_ptr_array_add (identities,
+              (gpointer) g_strdup_printf ("%s/%s/%s/%s",
+                  category, type, xmllang, name));
+        }
+      else if (g_str_equal (child->name, "feature"))
+        {
+          const gchar *var;
+          var = lm_message_node_get_attribute (child, "var");
+
+          if (NULL == var)
+            continue;
+
+          g_ptr_array_add (features, (gpointer) g_strdup (var));
+        }
+
+    }
+
+  str = gabble_presence_compute_xep0115_hash (features, identities);
+
+  g_ptr_array_free (features, TRUE);
+  g_ptr_array_free (identities, TRUE);
+
+  return str;
+}
+
+
+gchar *
+gabble_presence_compute_xep0115_hash_from_self_presence (GabbleConnection *self)
+{
+  GabblePresence *presence = self->self_presence;
+  GSList *features_list = capabilities_get_features (presence->caps);
+  GPtrArray *features = g_ptr_array_new ();
+  GPtrArray *identities = g_ptr_array_new ();
+  gchar *str;
+  GSList *i;
+
+  for (i = features_list; NULL != i; i = i->next)
+    {
+      const Feature *feat = (const Feature *) i->data;
+      g_ptr_array_add (features, (gpointer) feat->ns);
+    }
+
+  g_ptr_array_sort (features, feature_strcmp);
+
+  g_ptr_array_add (features, (gpointer) "client/pc//" PACKAGE_STRING);
+
+  str = gabble_presence_compute_xep0115_hash (features, identities);
+
+  g_ptr_array_free (features, TRUE);
+  g_ptr_array_free (identities, TRUE);
+  g_slist_free (features_list);
+
+  return str;
+}
+
diff --git a/src/presence.h b/src/presence.h
index af7883e..d6f2327 100644
--- a/src/presence.h
+++ b/src/presence.h
@@ -91,7 +91,9 @@ LmMessage *gabble_presence_as_message (GabblePresence *presence,
 gchar *gabble_presence_dump (GabblePresence *presence);
 
 
-gchar *gabble_presence_get_xep0115_hash (GabblePresence *presence);
+gchar *gabble_presence_compute_xep0115_hash_from_lm_node (LmMessageNode *node);
+gchar *gabble_presence_compute_xep0115_hash_from_self_presence (
+    GabbleConnection *self);
 
 G_END_DECLS
 
-- 
1.5.6.3




More information about the Telepathy-commits mailing list