[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