figure out fallbacks with omemo source id

Daniel Gultsch created

Change summary

src/main/java/eu/siacs/conversations/crypto/axolotl/AxolotlService.java     | 17 
src/main/java/eu/siacs/conversations/crypto/axolotl/XmppAxolotlMessage.java | 12 
src/main/java/eu/siacs/conversations/parser/MessageParser.java              | 29 
3 files changed, 55 insertions(+), 3 deletions(-)

Detailed changes

src/main/java/eu/siacs/conversations/crypto/axolotl/AxolotlService.java 🔗

@@ -206,6 +206,19 @@ public class AxolotlService implements OnAdvancedStreamFeaturesLoaded {
 			this.fillMap(store);
 		}
 
+		public Set<Jid> findCounterpartsForSourceId(Integer sid) {
+			Set<Jid> candidates = new HashSet<>();
+			synchronized (MAP_LOCK) {
+				for(Map.Entry<String,Map<Integer,XmppAxolotlSession>> entry : map.entrySet()) {
+					String key = entry.getKey();
+					if (entry.getValue().containsKey(sid)) {
+						candidates.add(Jid.of(key));
+					}
+				}
+			}
+			return candidates;
+		}
+
 		private void putDevicesForJid(String bareJid, List<Integer> deviceIds, SQLiteAxolotlStore store) {
 			for (Integer deviceId : deviceIds) {
 				SignalProtocolAddress axolotlAddress = new SignalProtocolAddress(bareJid, deviceId);
@@ -316,6 +329,10 @@ public class AxolotlService implements OnAdvancedStreamFeaturesLoaded {
 		return keys;
 	}
 
+	public Set<Jid> findCounterpartsBySourceId(int sid) {
+		return sessions.findCounterpartsForSourceId(sid);
+	}
+
 	public long getNumTrustedKeys(Jid jid) {
 		return axolotlStore.getContactNumTrustedKeys(jid.asBareJid().toString());
 	}

src/main/java/eu/siacs/conversations/crypto/axolotl/XmppAxolotlMessage.java 🔗

@@ -91,6 +91,18 @@ public class XmppAxolotlMessage {
 		}
 	}
 
+	public static int parseSourceId(final Element axolotlMessage) throws IllegalArgumentException {
+		final Element header = axolotlMessage.findChild(HEADER);
+		if (header == null) {
+			throw new IllegalArgumentException("No header found");
+		}
+		try {
+			return Integer.parseInt(header.getAttribute(SOURCEID));
+		} catch (NumberFormatException e) {
+			throw new IllegalArgumentException("invalid source id");
+		}
+	}
+
 	private XmppAxolotlMessage(final Element axolotlMessage, final Jid from) throws IllegalArgumentException {
 		this.from = from;
 		Element header = axolotlMessage.findChild(HEADER);

src/main/java/eu/siacs/conversations/parser/MessageParser.java 🔗

@@ -6,6 +6,7 @@ import android.util.Pair;
 import java.text.SimpleDateFormat;
 import java.util.ArrayList;
 import java.util.Arrays;
+import java.util.Collections;
 import java.util.Date;
 import java.util.List;
 import java.util.Locale;
@@ -368,17 +369,39 @@ public class MessageParser extends AbstractParser implements OnMessagePacketRece
 				message = new Message(conversation, pgpEncrypted, Message.ENCRYPTION_PGP, status);
 			} else if (axolotlEncrypted != null && Config.supportOmemo()) {
 				Jid origin;
+				Set<Jid> fallbacksBySourceId = Collections.emptySet();
 				if (conversationMultiMode) {
 					final Jid fallback = conversation.getMucOptions().getTrueCounterpart(counterpart);
 					origin = getTrueCounterpart(query != null ? mucUserElement : null, fallback);
 					if (origin == null) {
-						Log.d(Config.LOGTAG, "axolotl message in non anonymous conference received");
+						try {
+							fallbacksBySourceId = account.getAxolotlService().findCounterpartsBySourceId(XmppAxolotlMessage.parseSourceId(axolotlEncrypted));
+						} catch (IllegalArgumentException e) {
+							//ignoring
+						}
+					}
+					if (origin == null && fallbacksBySourceId.size() == 0) {
+						Log.d(Config.LOGTAG, "axolotl message in anonymous conference received and no possible fallbacks");
 						return;
 					}
 				} else {
+					fallbacksBySourceId = Collections.emptySet();
 					origin = from;
 				}
-				message = parseAxolotlChat(axolotlEncrypted, origin, conversation, status, query != null);
+				if (origin != null) {
+					message = parseAxolotlChat(axolotlEncrypted, origin, conversation, status, query != null);
+				} else {
+					Message trial = null;
+					for(Jid fallback : fallbacksBySourceId) {
+						trial = parseAxolotlChat(axolotlEncrypted, fallback, conversation, status, query != null);
+						if (trial != null) {
+							Log.d(Config.LOGTAG,account.getJid().asBareJid()+": decoded muc message using fallback");
+							origin = fallback;
+							break;
+						}
+					}
+					message = trial;
+				}
 				if (message == null) {
 					if (query == null &&  extractChatState(mXmppConnectionService.find(account, counterpart.asBareJid()), isTypeGroupChat, packet)) {
 						mXmppConnectionService.updateConversationUi();
@@ -576,7 +599,7 @@ public class MessageParser extends AbstractParser implements OnMessagePacketRece
 					final Jid fallback = conversation.getMucOptions().getTrueCounterpart(counterpart);
 					origin = getTrueCounterpart(query != null ? mucUserElement : null, fallback);
 					if (origin == null) {
-						Log.d(Config.LOGTAG, "omemo key transport message in non anonymous conference received");
+						Log.d(Config.LOGTAG, "omemo key transport message in anonymous conference received");
 						return;
 					}
 				} else if (isTypeGroupChat) {