put omemo fingerprint in own uri (qr code / nfc)

Daniel Gultsch created

Change summary

src/main/java/eu/siacs/conversations/crypto/axolotl/AxolotlService.java     |  8 
src/main/java/eu/siacs/conversations/crypto/axolotl/XmppAxolotlSession.java |  2 
src/main/java/eu/siacs/conversations/entities/Account.java                  | 43 
src/main/java/eu/siacs/conversations/services/XmppConnectionService.java    | 23 
src/main/java/eu/siacs/conversations/ui/StartConversationActivity.java      | 16 
src/main/java/eu/siacs/conversations/utils/XmppUri.java                     |  5 
6 files changed, 80 insertions(+), 17 deletions(-)

Detailed changes

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

@@ -102,6 +102,10 @@ public class AxolotlService implements OnAdvancedStreamFeaturesLoaded {
 		axolotlStore.preVerifyFingerprint(contact.getAccount(), contact.getJid().toBareJid().toPreppedString(), fingerprint);
 	}
 
+	public void preVerifyFingerprint(Account account, String fingerprint) {
+		axolotlStore.preVerifyFingerprint(account, account.getJid().toBareJid().toPreppedString(), fingerprint);
+	}
+
 	private static class AxolotlAddressMap<T> {
 		protected Map<String, Map<Integer, T>> map;
 		protected final Object MAP_LOCK = new Object();
@@ -293,11 +297,13 @@ public class AxolotlService implements OnAdvancedStreamFeaturesLoaded {
 		return new AxolotlAddress(jid.toPreppedString(), 0);
 	}
 
-	private Set<XmppAxolotlSession> findOwnSessions() {
+	public Set<XmppAxolotlSession> findOwnSessions() {
 		AxolotlAddress ownAddress = getAddressForJid(account.getJid().toBareJid());
 		return new HashSet<>(this.sessions.getAll(ownAddress).values());
 	}
 
+
+
 	private Set<XmppAxolotlSession> findSessionsForContact(Contact contact) {
 		AxolotlAddress contactAddress = getAddressForJid(contact.getJid());
 		return new HashSet<>(this.sessions.getAll(contactAddress).values());

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

@@ -76,7 +76,7 @@ public class XmppAxolotlSession {
 		sqLiteAxolotlStore.setFingerprintStatus(getFingerprint(), status);
 	}
 
-	protected FingerprintStatus getTrust() {
+	public FingerprintStatus getTrust() {
 		FingerprintStatus status = sqLiteAxolotlStore.getFingerprintStatus(getFingerprint());
 		return (status == null) ? FingerprintStatus.createActiveUndecided() : status;
 	}

src/main/java/eu/siacs/conversations/entities/Account.java 🔗

@@ -15,6 +15,7 @@ import org.json.JSONObject;
 
 import java.security.PublicKey;
 import java.security.interfaces.DSAPublicKey;
+import java.util.ArrayList;
 import java.util.Collection;
 import java.util.HashSet;
 import java.util.List;
@@ -24,7 +25,9 @@ import java.util.concurrent.CopyOnWriteArraySet;
 import eu.siacs.conversations.R;
 import eu.siacs.conversations.crypto.OtrService;
 import eu.siacs.conversations.crypto.axolotl.AxolotlService;
+import eu.siacs.conversations.crypto.axolotl.XmppAxolotlSession;
 import eu.siacs.conversations.services.XmppConnectionService;
+import eu.siacs.conversations.utils.XmppUri;
 import eu.siacs.conversations.xmpp.XmppConnection;
 import eu.siacs.conversations.xmpp.jid.InvalidJidException;
 import eu.siacs.conversations.xmpp.jid.Jid;
@@ -599,12 +602,44 @@ public class Account extends AbstractEntity {
 	}
 
 	public String getShareableUri() {
-		final String fingerprint = this.getOtrFingerprint();
-		if (fingerprint != null) {
-			return "xmpp:" + this.getJid().toBareJid().toString() + "?otr-fingerprint="+fingerprint;
+		List<XmppUri.Fingerprint> fingerprints = this.getFingerprints();
+		String uri = "xmpp:"+this.getJid().toBareJid().toString();
+		if (fingerprints.size() > 0) {
+			StringBuilder builder = new StringBuilder(uri);
+			builder.append('?');
+			for(int i = 0; i < fingerprints.size(); ++i) {
+				XmppUri.FingerprintType type = fingerprints.get(i).type;
+				if (type == XmppUri.FingerprintType.OMEMO) {
+					builder.append(XmppUri.OMEMO_URI_PARAM);
+					builder.append(fingerprints.get(i).deviceId);
+				} else if (type == XmppUri.FingerprintType.OTR) {
+					builder.append(XmppUri.OTR_URI_PARAM);
+				}
+				builder.append('=');
+				builder.append(fingerprints.get(i).fingerprint);
+				if (i != fingerprints.size() -1) {
+					builder.append(';');
+				}
+			}
+			return builder.toString();
 		} else {
-			return "xmpp:" + this.getJid().toBareJid().toString();
+			return uri;
+		}
+	}
+
+	private List<XmppUri.Fingerprint> getFingerprints() {
+		ArrayList<XmppUri.Fingerprint> fingerprints = new ArrayList<>();
+		final String otr = this.getOtrFingerprint();
+		if (otr != null) {
+			fingerprints.add(new XmppUri.Fingerprint(XmppUri.FingerprintType.OTR,otr));
+		}
+		fingerprints.add(new XmppUri.Fingerprint(XmppUri.FingerprintType.OMEMO,axolotlService.getOwnFingerprint().substring(2),axolotlService.getOwnDeviceId()));
+		for(XmppAxolotlSession session : axolotlService.findOwnSessions()) {
+			if (session.getTrust().isVerified() && session.getTrust().isActive()) {
+				fingerprints.add(new XmppUri.Fingerprint(XmppUri.FingerprintType.OMEMO,session.getFingerprint().substring(2).replaceAll("\\s",""),session.getRemoteAddress().getDeviceId()));
+			}
 		}
+		return fingerprints;
 	}
 
 	public boolean isBlocked(final ListItem contact) {

src/main/java/eu/siacs/conversations/services/XmppConnectionService.java 🔗

@@ -67,6 +67,7 @@ import eu.siacs.conversations.crypto.PgpEngine;
 import eu.siacs.conversations.crypto.axolotl.AxolotlService;
 import eu.siacs.conversations.crypto.axolotl.FingerprintStatus;
 import eu.siacs.conversations.crypto.axolotl.XmppAxolotlMessage;
+import eu.siacs.conversations.crypto.axolotl.XmppAxolotlSession;
 import eu.siacs.conversations.entities.Account;
 import eu.siacs.conversations.entities.Blockable;
 import eu.siacs.conversations.entities.Bookmark;
@@ -3633,6 +3634,28 @@ public class XmppConnectionService extends Service {
 		}
 	}
 
+	public boolean verifyFingerprints(Account account, List<XmppUri.Fingerprint> fingerprints) {
+		final AxolotlService axolotlService = account.getAxolotlService();
+		boolean verifiedSomething = false;
+		for(XmppUri.Fingerprint fp : fingerprints) {
+			if (fp.type == XmppUri.FingerprintType.OMEMO) {
+				String fingerprint = "05"+fp.fingerprint.replaceAll("\\s","");
+				Log.d(Config.LOGTAG,"trying to verify own fp="+fingerprint);
+				FingerprintStatus fingerprintStatus = axolotlService.getFingerprintTrust(fingerprint);
+				if (fingerprintStatus != null) {
+					if (!fingerprintStatus.isVerified()) {
+						axolotlService.setFingerprintTrust(fingerprint,fingerprintStatus.toVerified());
+						verifiedSomething = true;
+					}
+				} else {
+					axolotlService.preVerifyFingerprint(account,fingerprint);
+					verifiedSomething = true;
+				}
+			}
+		}
+		return verifiedSomething;
+	}
+
 	public interface OnMamPreferencesFetched {
 		void onPreferencesFetched(Element prefs);
 		void onPreferencesFetchFailed();

src/main/java/eu/siacs/conversations/ui/StartConversationActivity.java 🔗

@@ -842,9 +842,13 @@ public class StartConversationActivity extends XmppActivity implements OnRosterU
     }
 
     private boolean handleJid(Invite invite) {
-        Log.d(Config.LOGTAG,"handling invite for "+invite.getJid());
-        for(XmppUri.Fingerprint fp : invite.getFingerprints()) {
-            Log.d(Config.LOGTAG,fp.toString());
+        Account account = xmppConnectionService.findAccountByJid(invite.getJid());
+        if (account != null && invite.hasFingerprints()) {
+            if (xmppConnectionService.verifyFingerprints(account,invite.getFingerprints())) {
+                switchToAccount(account);
+                finish();
+                return true;
+            }
         }
         List<Contact> contacts = xmppConnectionService.findContacts(invite.getJid());
         if (invite.isMuc()) {
@@ -864,12 +868,6 @@ public class StartConversationActivity extends XmppActivity implements OnRosterU
             if (invite.hasFingerprints()) {
                 xmppConnectionService.verifyFingerprints(contact,invite.getFingerprints());
             }
-            /*if (invite.getFingerprint() != null) {
-                if (contact.addOtrFingerprint(invite.getFingerprint())) {
-                    Log.d(Config.LOGTAG, "added new fingerprint");
-                    xmppConnectionService.syncRosterToDisk(contact.getAccount());
-                }
-            }*/
             switchToConversation(contact);
             return true;
         } else {

src/main/java/eu/siacs/conversations/utils/XmppUri.java 🔗

@@ -17,7 +17,8 @@ public class XmppUri {
 	protected boolean muc;
 	protected List<Fingerprint> fingerprints = new ArrayList<>();
 
-	private static final String OMEMO_URI_PARAM = "omemo-sid-";
+	public static final String OMEMO_URI_PARAM = "omemo-sid-";
+	public static final String OTR_URI_PARAM = "otr-fingerprint";
 
 	public XmppUri(String uri) {
 		try {
@@ -85,7 +86,7 @@ public class XmppUri {
 			if (parts.length == 2) {
 				String key = parts[0].toLowerCase(Locale.US);
 				String value = parts[1];
-				if ("otr-fingerprint".equals(key)) {
+				if (OTR_URI_PARAM.equals(key)) {
 					fingerprints.add(new Fingerprint(FingerprintType.OTR,value));
 				}
 				if (key.startsWith(OMEMO_URI_PARAM)) {