From 1e6aed759b624e1f73c1cbdf2920827268e22990 Mon Sep 17 00:00:00 2001 From: Daniel Gultsch Date: Thu, 19 Jan 2023 20:53:42 +0100 Subject: [PATCH] check caps hash after retrieving them --- .../android/xmpp/XmppConnection.java | 3 +- .../android/xmpp/manager/DiscoManager.java | 62 ++++++++++++++----- .../xmpp/processor/PresenceProcessor.java | 2 +- 3 files changed, 51 insertions(+), 16 deletions(-) diff --git a/src/main/java/im/conversations/android/xmpp/XmppConnection.java b/src/main/java/im/conversations/android/xmpp/XmppConnection.java index 3c169f6ef..5a64a3eb0 100644 --- a/src/main/java/im/conversations/android/xmpp/XmppConnection.java +++ b/src/main/java/im/conversations/android/xmpp/XmppConnection.java @@ -1884,7 +1884,8 @@ public class XmppConnection implements Runnable { final var nodeHash = this.streamFeatures.getCapabilities(); final var domainDiscoItem = Entity.discoItem(account.address.getDomain()); if (nodeHash != null) { - discoFutures.add(discoManager.info(domainDiscoItem, nodeHash.node, nodeHash.hash)); + discoFutures.add( + discoManager.infoOrCache(domainDiscoItem, nodeHash.node, nodeHash.hash)); } else { discoFutures.add(discoManager.info(domainDiscoItem)); } diff --git a/src/main/java/im/conversations/android/xmpp/manager/DiscoManager.java b/src/main/java/im/conversations/android/xmpp/manager/DiscoManager.java index 00eac5710..a99ec7cc8 100644 --- a/src/main/java/im/conversations/android/xmpp/manager/DiscoManager.java +++ b/src/main/java/im/conversations/android/xmpp/manager/DiscoManager.java @@ -1,8 +1,10 @@ package im.conversations.android.xmpp.manager; import android.content.Context; +import androidx.annotation.NonNull; import androidx.annotation.Nullable; import com.google.common.collect.Collections2; +import com.google.common.io.BaseEncoding; import com.google.common.util.concurrent.Futures; import com.google.common.util.concurrent.ListenableFuture; import com.google.common.util.concurrent.MoreExecutors; @@ -15,6 +17,7 @@ import im.conversations.android.xmpp.XmppConnection; import im.conversations.android.xmpp.model.disco.info.InfoQuery; import im.conversations.android.xmpp.model.disco.items.Item; import im.conversations.android.xmpp.model.disco.items.ItemsQuery; +import java.util.Arrays; import java.util.Collection; import java.util.List; import java.util.Objects; @@ -29,22 +32,30 @@ public class DiscoManager extends AbstractManager { return info(entity, null); } - public ListenableFuture info( + public ListenableFuture infoOrCache( final Entity entity, @Nullable final String node, final EntityCapabilities.Hash hash) { - final String capabilityNode = hash.capabilityNode(node); - if (getDatabase().discoDao().set(getAccount(), entity, capabilityNode, hash)) { + if (getDatabase().discoDao().set(getAccount(), entity, node, hash)) { return Futures.immediateFuture(null); } return Futures.transform( - info(entity, capabilityNode), f -> null, MoreExecutors.directExecutor()); + info(entity, node, hash), f -> null, MoreExecutors.directExecutor()); } - public ListenableFuture info(final Entity entity, final String node) { + public ListenableFuture info( + @NonNull final Entity entity, @Nullable final String node) { + return info(entity, node, null); + } + + public ListenableFuture info( + final Entity entity, + @Nullable final String node, + @Nullable final EntityCapabilities.Hash hash) { + final var requestNode = hash != null && node != null ? hash.capabilityNode(node) : node; final var iqRequest = new IqPacket(IqPacket.TYPE.GET); iqRequest.setTo(entity.address); final var infoQueryRequest = new InfoQuery(); - if (node != null) { - infoQueryRequest.setNode(node); + if (requestNode != null) { + infoQueryRequest.setNode(requestNode); } iqRequest.addChild(infoQueryRequest); final var future = connection.sendIqPacket(iqRequest); @@ -57,20 +68,45 @@ public class DiscoManager extends AbstractManager { if (infoQuery == null) { throw new IllegalStateException("Response did not have query child"); } - if (!Objects.equals(node, infoQuery.getNode())) { + if (!Objects.equals(requestNode, infoQuery.getNode())) { throw new IllegalStateException( "Node in response did not match node in request"); } - final byte[] caps = EntityCapabilities.hash(infoQuery).hash; - final byte[] caps2 = EntityCapabilities2.hash(infoQuery).hash; + final var caps = EntityCapabilities.hash(infoQuery); + final var caps2 = EntityCapabilities2.hash(infoQuery); + if (hash instanceof EntityCapabilities.EntityCapsHash) { + checkMatch( + (EntityCapabilities.EntityCapsHash) hash, + caps, + EntityCapabilities.EntityCapsHash.class); + } + if (hash instanceof EntityCapabilities2.EntityCaps2Hash) { + checkMatch( + (EntityCapabilities2.EntityCaps2Hash) hash, + caps2, + EntityCapabilities2.EntityCaps2Hash.class); + } getDatabase() .discoDao() - .set(getAccount(), entity, node, caps, caps2, infoQuery); + .set(getAccount(), entity, node, caps.hash, caps2.hash, infoQuery); return infoQuery; }, MoreExecutors.directExecutor()); } + private void checkMatch( + final H expected, final H was, final Class clazz) { + if (Arrays.equals(expected.hash, was.hash)) { + return; + } + throw new IllegalStateException( + String.format( + "%s mismatch. Expected %s was %s", + clazz.getSimpleName(), + BaseEncoding.base64().encode(expected.hash), + BaseEncoding.base64().encode(was.hash))); + } + public ListenableFuture> items(final Entity.DiscoItem entity) { final var iqPacket = new IqPacket(IqPacket.TYPE.GET); iqPacket.setTo(entity.address); @@ -97,11 +133,9 @@ public class DiscoManager extends AbstractManager { return Futures.transformAsync( itemsFutures, items -> { - final var filtered = - Collections2.filter(items, i -> Objects.nonNull(i.getJid())); Collection> infoFutures = Collections2.transform( - filtered, i -> info(Entity.discoItem(i.getJid()), i.getNode())); + items, i -> info(Entity.discoItem(i.getJid()), i.getNode())); return Futures.allAsList(infoFutures); }, MoreExecutors.directExecutor()); diff --git a/src/main/java/im/conversations/android/xmpp/processor/PresenceProcessor.java b/src/main/java/im/conversations/android/xmpp/processor/PresenceProcessor.java index 54a8fc26e..68143add7 100644 --- a/src/main/java/im/conversations/android/xmpp/processor/PresenceProcessor.java +++ b/src/main/java/im/conversations/android/xmpp/processor/PresenceProcessor.java @@ -43,7 +43,7 @@ public class PresenceProcessor extends XmppConnection.Delegate implements Consum final var nodeHash = presencePacket.getCapabilities(); if (nodeHash != null) { getManager(DiscoManager.class) - .info(Entity.presence(entity), nodeHash.node, nodeHash.hash); + .infoOrCache(Entity.presence(entity), nodeHash.node, nodeHash.hash); } } }