aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorDaniel Gultsch <daniel@gultsch.de>2016-11-17 20:09:42 +0100
committerDaniel Gultsch <daniel@gultsch.de>2016-11-17 20:09:42 +0100
commit7e2e42cb11fdd8fc126795f6005956ccffe084ff (patch)
treee2523c145208bcb80c82766a1633d6b015b7c565
parent3f3b360eeeabf06c3b7c43ff05ad6ed8cf307473 (diff)
parse omemo fingerprints from uris
-rw-r--r--src/main/java/eu/siacs/conversations/crypto/axolotl/AxolotlService.java27
-rw-r--r--src/main/java/eu/siacs/conversations/crypto/axolotl/FingerprintStatus.java14
-rw-r--r--src/main/java/eu/siacs/conversations/crypto/axolotl/SQLiteAxolotlStore.java16
-rw-r--r--src/main/java/eu/siacs/conversations/crypto/axolotl/XmppAxolotlSession.java2
-rw-r--r--src/main/java/eu/siacs/conversations/persistance/DatabaseBackend.java31
-rw-r--r--src/main/java/eu/siacs/conversations/services/XmppConnectionService.java25
-rw-r--r--src/main/java/eu/siacs/conversations/ui/StartConversationActivity.java19
-rw-r--r--src/main/java/eu/siacs/conversations/ui/TrustKeysActivity.java5
-rw-r--r--src/main/java/eu/siacs/conversations/ui/VerifyOTRActivity.java5
-rw-r--r--src/main/java/eu/siacs/conversations/utils/XmppUri.java71
-rw-r--r--src/main/res/values/strings.xml1
11 files changed, 172 insertions, 44 deletions
diff --git a/src/main/java/eu/siacs/conversations/crypto/axolotl/AxolotlService.java b/src/main/java/eu/siacs/conversations/crypto/axolotl/AxolotlService.java
index 211ec0e7..2ee0501a 100644
--- a/src/main/java/eu/siacs/conversations/crypto/axolotl/AxolotlService.java
+++ b/src/main/java/eu/siacs/conversations/crypto/axolotl/AxolotlService.java
@@ -98,6 +98,10 @@ public class AxolotlService implements OnAdvancedStreamFeaturesLoaded {
return false;
}
+ public void preVerifyFingerprint(Contact contact, String fingerprint) {
+ axolotlStore.preVerifyFingerprint(contact.getAccount(), contact.getJid().toBareJid().toPreppedString(), fingerprint);
+ }
+
private static class AxolotlAddressMap<T> {
protected Map<String, Map<Integer, T>> map;
protected final Object MAP_LOCK = new Object();
@@ -200,7 +204,7 @@ public class AxolotlService implements OnAdvancedStreamFeaturesLoaded {
public void put(AxolotlAddress address, XmppAxolotlSession value) {
super.put(address, value);
value.setNotFresh();
- xmppConnectionService.syncRosterToDisk(account);
+ xmppConnectionService.syncRosterToDisk(account); //TODO why?
}
public void put(XmppAxolotlSession session) {
@@ -417,7 +421,7 @@ public class AxolotlService implements OnAdvancedStreamFeaturesLoaded {
}
public void purgeKey(final String fingerprint) {
- axolotlStore.setFingerprintTrust(fingerprint.replaceAll("\\s", ""), FingerprintStatus.createCompromised());
+ axolotlStore.setFingerprintStatus(fingerprint.replaceAll("\\s", ""), FingerprintStatus.createCompromised());
}
public void publishOwnDeviceIdIfNeeded() {
@@ -690,7 +694,7 @@ public class AxolotlService implements OnAdvancedStreamFeaturesLoaded {
}
public void setFingerprintTrust(String fingerprint, FingerprintStatus status) {
- axolotlStore.setFingerprintTrust(fingerprint, status);
+ axolotlStore.setFingerprintStatus(fingerprint, status);
}
private void verifySessionWithPEP(final XmppAxolotlSession session) {
@@ -749,14 +753,15 @@ public class AxolotlService implements OnAdvancedStreamFeaturesLoaded {
private void finishBuildingSessionsFromPEP(final AxolotlAddress address) {
AxolotlAddress ownAddress = new AxolotlAddress(account.getJid().toBareJid().toPreppedString(), 0);
- if (!fetchStatusMap.getAll(ownAddress).containsValue(FetchStatus.PENDING)
- && !fetchStatusMap.getAll(address).containsValue(FetchStatus.PENDING)) {
+ Map<Integer, FetchStatus> own = fetchStatusMap.getAll(ownAddress);
+ Map<Integer, FetchStatus> remote = fetchStatusMap.getAll(address);
+ if (!own.containsValue(FetchStatus.PENDING) && !remote.containsValue(FetchStatus.PENDING)) {
FetchStatus report = null;
- if (fetchStatusMap.getAll(ownAddress).containsValue(FetchStatus.SUCCESS_VERIFIED)
- | fetchStatusMap.getAll(address).containsValue(FetchStatus.SUCCESS_VERIFIED)) {
+ if (own.containsValue(FetchStatus.SUCCESS) || remote.containsValue(FetchStatus.SUCCESS)) {
+ report = FetchStatus.SUCCESS;
+ } else if (own.containsValue(FetchStatus.SUCCESS_VERIFIED) || remote.containsValue(FetchStatus.SUCCESS_VERIFIED)) {
report = FetchStatus.SUCCESS_VERIFIED;
- } else if (fetchStatusMap.getAll(ownAddress).containsValue(FetchStatus.ERROR)
- || fetchStatusMap.getAll(address).containsValue(FetchStatus.ERROR)) {
+ } else if (own.containsValue(FetchStatus.ERROR) || remote.containsValue(FetchStatus.ERROR)) {
report = FetchStatus.ERROR;
}
mXmppConnectionService.keyStatusUpdated(report);
@@ -812,7 +817,9 @@ public class AxolotlService implements OnAdvancedStreamFeaturesLoaded {
if (Config.X509_VERIFICATION) {
verifySessionWithPEP(session);
} else {
- fetchStatusMap.put(address, FetchStatus.SUCCESS);
+ FingerprintStatus status = getFingerprintTrust(bundle.getIdentityKey().getFingerprint().replaceAll("\\s",""));
+ boolean verified = status != null && status.isVerified();
+ fetchStatusMap.put(address, verified ? FetchStatus.SUCCESS_VERIFIED : FetchStatus.SUCCESS);
finishBuildingSessionsFromPEP(address);
}
} catch (UntrustedIdentityException | InvalidKeyException e) {
diff --git a/src/main/java/eu/siacs/conversations/crypto/axolotl/FingerprintStatus.java b/src/main/java/eu/siacs/conversations/crypto/axolotl/FingerprintStatus.java
index 15bd9542..b594b5de 100644
--- a/src/main/java/eu/siacs/conversations/crypto/axolotl/FingerprintStatus.java
+++ b/src/main/java/eu/siacs/conversations/crypto/axolotl/FingerprintStatus.java
@@ -114,6 +114,20 @@ public class FingerprintStatus {
return status;
}
+ public FingerprintStatus toVerified() {
+ FingerprintStatus status = new FingerprintStatus();
+ status.active = active;
+ status.trust = Trust.VERIFIED;
+ return status;
+ }
+
+ public static FingerprintStatus createInactiveVerified() {
+ final FingerprintStatus status = new FingerprintStatus();
+ status.trust = Trust.VERIFIED;
+ status.active = false;
+ return status;
+ }
+
public enum Trust {
COMPROMISED,
UNDECIDED,
diff --git a/src/main/java/eu/siacs/conversations/crypto/axolotl/SQLiteAxolotlStore.java b/src/main/java/eu/siacs/conversations/crypto/axolotl/SQLiteAxolotlStore.java
index 4a27601f..a3647be7 100644
--- a/src/main/java/eu/siacs/conversations/crypto/axolotl/SQLiteAxolotlStore.java
+++ b/src/main/java/eu/siacs/conversations/crypto/axolotl/SQLiteAxolotlStore.java
@@ -187,7 +187,15 @@ public class SQLiteAxolotlStore implements AxolotlStore {
@Override
public void saveIdentity(String name, IdentityKey identityKey) {
if (!mXmppConnectionService.databaseBackend.loadIdentityKeys(account, name).contains(identityKey)) {
- mXmppConnectionService.databaseBackend.storeIdentityKey(account, name, identityKey);
+ String fingerprint = identityKey.getFingerprint().replaceAll("\\s", "");
+ FingerprintStatus status = getFingerprintStatus(fingerprint);
+ if (status == null) {
+ status = FingerprintStatus.createActiveUndecided(); //default for new keys
+ } else {
+ status = status.toActive();
+ }
+ mXmppConnectionService.databaseBackend.storeIdentityKey(account, name, identityKey, status);
+ trustCache.remove(fingerprint);
}
}
@@ -214,7 +222,7 @@ public class SQLiteAxolotlStore implements AxolotlStore {
return (fingerprint == null)? null : trustCache.get(fingerprint);
}
- public void setFingerprintTrust(String fingerprint, FingerprintStatus status) {
+ public void setFingerprintStatus(String fingerprint, FingerprintStatus status) {
mXmppConnectionService.databaseBackend.setIdentityKeyTrust(account, fingerprint, status);
trustCache.remove(fingerprint);
}
@@ -430,4 +438,8 @@ public class SQLiteAxolotlStore implements AxolotlStore {
public void removeSignedPreKey(int signedPreKeyId) {
mXmppConnectionService.databaseBackend.deleteSignedPreKey(account, signedPreKeyId);
}
+
+ public void preVerifyFingerprint(Account account, String name, String fingerprint) {
+ mXmppConnectionService.databaseBackend.storePreVerification(account,name,fingerprint,FingerprintStatus.createInactiveVerified());
+ }
}
diff --git a/src/main/java/eu/siacs/conversations/crypto/axolotl/XmppAxolotlSession.java b/src/main/java/eu/siacs/conversations/crypto/axolotl/XmppAxolotlSession.java
index 706a5c46..b1d071a4 100644
--- a/src/main/java/eu/siacs/conversations/crypto/axolotl/XmppAxolotlSession.java
+++ b/src/main/java/eu/siacs/conversations/crypto/axolotl/XmppAxolotlSession.java
@@ -73,7 +73,7 @@ public class XmppAxolotlSession {
}
protected void setTrust(FingerprintStatus status) {
- sqLiteAxolotlStore.setFingerprintTrust(getFingerprint(), status);
+ sqLiteAxolotlStore.setFingerprintStatus(getFingerprint(), status);
}
protected FingerprintStatus getTrust() {
diff --git a/src/main/java/eu/siacs/conversations/persistance/DatabaseBackend.java b/src/main/java/eu/siacs/conversations/persistance/DatabaseBackend.java
index 71567356..1e50ce9c 100644
--- a/src/main/java/eu/siacs/conversations/persistance/DatabaseBackend.java
+++ b/src/main/java/eu/siacs/conversations/persistance/DatabaseBackend.java
@@ -1106,7 +1106,12 @@ public class DatabaseBackend extends SQLiteOpenHelper {
continue;
}
try {
- identityKeys.add(new IdentityKey(Base64.decode(cursor.getString(cursor.getColumnIndex(SQLiteAxolotlStore.KEY)), Base64.DEFAULT), 0));
+ String key = cursor.getString(cursor.getColumnIndex(SQLiteAxolotlStore.KEY));
+ if (key != null) {
+ identityKeys.add(new IdentityKey(Base64.decode(key, Base64.DEFAULT), 0));
+ } else {
+ Log.d(Config.LOGTAG, AxolotlService.getLogprefix(account) + "Missing key (possibly preverified) in database for account" + account.getJid().toBareJid() + ", address: " + name);
+ }
} catch (InvalidKeyException e) {
Log.d(Config.LOGTAG, AxolotlService.getLogprefix(account) + "Encountered invalid IdentityKey in database for account" + account.getJid().toBareJid() + ", address: " + name);
}
@@ -1134,10 +1139,6 @@ public class DatabaseBackend extends SQLiteOpenHelper {
);
}
- private void storeIdentityKey(Account account, String name, boolean own, String fingerprint, String base64Serialized) {
- storeIdentityKey(account, name, own, fingerprint, base64Serialized, FingerprintStatus.createActiveUndecided());
- }
-
private void storeIdentityKey(Account account, String name, boolean own, String fingerprint, String base64Serialized, FingerprintStatus status) {
SQLiteDatabase db = this.getWritableDatabase();
ContentValues values = new ContentValues();
@@ -1147,6 +1148,22 @@ public class DatabaseBackend extends SQLiteOpenHelper {
values.put(SQLiteAxolotlStore.FINGERPRINT, fingerprint);
values.put(SQLiteAxolotlStore.KEY, base64Serialized);
values.putAll(status.toContentValues());
+ String where = SQLiteAxolotlStore.ACCOUNT+"=? AND "+SQLiteAxolotlStore.NAME+"=? AND "+SQLiteAxolotlStore.FINGERPRINT+" =?";
+ String[] whereArgs = {account.getUuid(),name,fingerprint};
+ int rows = db.update(SQLiteAxolotlStore.IDENTITIES_TABLENAME,values,where,whereArgs);
+ if (rows == 0) {
+ db.insert(SQLiteAxolotlStore.IDENTITIES_TABLENAME, null, values);
+ }
+ }
+
+ public void storePreVerification(Account account, String name, String fingerprint, FingerprintStatus status) {
+ SQLiteDatabase db = this.getWritableDatabase();
+ ContentValues values = new ContentValues();
+ values.put(SQLiteAxolotlStore.ACCOUNT, account.getUuid());
+ values.put(SQLiteAxolotlStore.NAME, name);
+ values.put(SQLiteAxolotlStore.OWN, 0);
+ values.put(SQLiteAxolotlStore.FINGERPRINT, fingerprint);
+ values.putAll(status.toContentValues());
db.insert(SQLiteAxolotlStore.IDENTITIES_TABLENAME, null, values);
}
@@ -1227,8 +1244,8 @@ public class DatabaseBackend extends SQLiteOpenHelper {
}
}
- public void storeIdentityKey(Account account, String name, IdentityKey identityKey) {
- storeIdentityKey(account, name, false, identityKey.getFingerprint().replaceAll("\\s", ""), Base64.encodeToString(identityKey.serialize(), Base64.DEFAULT));
+ public void storeIdentityKey(Account account, String name, IdentityKey identityKey, FingerprintStatus status) {
+ storeIdentityKey(account, name, false, identityKey.getFingerprint().replaceAll("\\s", ""), Base64.encodeToString(identityKey.serialize(), Base64.DEFAULT), status);
}
public void storeOwnIdentityKeyPair(Account account, IdentityKeyPair identityKeyPair) {
diff --git a/src/main/java/eu/siacs/conversations/services/XmppConnectionService.java b/src/main/java/eu/siacs/conversations/services/XmppConnectionService.java
index 9ebbcf63..dc52e7cf 100644
--- a/src/main/java/eu/siacs/conversations/services/XmppConnectionService.java
+++ b/src/main/java/eu/siacs/conversations/services/XmppConnectionService.java
@@ -65,6 +65,7 @@ import eu.siacs.conversations.R;
import eu.siacs.conversations.crypto.PgpDecryptionService;
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.entities.Account;
import eu.siacs.conversations.entities.Blockable;
@@ -102,6 +103,7 @@ import eu.siacs.conversations.utils.PhoneHelper;
import eu.siacs.conversations.utils.ReplacingSerialSingleThreadExecutor;
import eu.siacs.conversations.utils.SerialSingleThreadExecutor;
import eu.siacs.conversations.utils.Xmlns;
+import eu.siacs.conversations.utils.XmppUri;
import eu.siacs.conversations.xml.Element;
import eu.siacs.conversations.xmpp.OnBindListener;
import eu.siacs.conversations.xmpp.OnContactStatusChanged;
@@ -3608,6 +3610,29 @@ public class XmppConnectionService extends Service {
});
}
+ public void verifyFingerprints(Contact contact, List<XmppUri.Fingerprint> fingerprints) {
+ boolean needsRosterWrite = false;
+ final AxolotlService axolotlService = contact.getAccount().getAxolotlService();
+ for(XmppUri.Fingerprint fp : fingerprints) {
+ if (fp.type == XmppUri.FingerprintType.OTR) {
+ needsRosterWrite |= contact.addOtrFingerprint(fp.fingerprint);
+ } else if (fp.type == XmppUri.FingerprintType.OMEMO) {
+ String fingerprint = "05"+fp.fingerprint.replaceAll("\\s","");
+ FingerprintStatus fingerprintStatus = axolotlService.getFingerprintTrust(fingerprint);
+ if (fingerprintStatus != null) {
+ if (!fingerprintStatus.isVerified()) {
+ axolotlService.setFingerprintTrust(fingerprint,fingerprintStatus.toVerified());
+ }
+ } else {
+ axolotlService.preVerifyFingerprint(contact,fingerprint);
+ }
+ }
+ }
+ if (needsRosterWrite) {
+ syncRosterToDisk(contact.getAccount());
+ }
+ }
+
public interface OnMamPreferencesFetched {
void onPreferencesFetched(Element prefs);
void onPreferencesFetchFailed();
diff --git a/src/main/java/eu/siacs/conversations/ui/StartConversationActivity.java b/src/main/java/eu/siacs/conversations/ui/StartConversationActivity.java
index ec5559ae..b1609adf 100644
--- a/src/main/java/eu/siacs/conversations/ui/StartConversationActivity.java
+++ b/src/main/java/eu/siacs/conversations/ui/StartConversationActivity.java
@@ -397,11 +397,11 @@ public class StartConversationActivity extends XmppActivity implements OnRosterU
}
@SuppressLint("InflateParams")
- protected void showCreateContactDialog(final String prefilledJid, final String fingerprint) {
+ protected void showCreateContactDialog(final String prefilledJid, final Invite invite) {
EnterJidDialog dialog = new EnterJidDialog(
this, mKnownHosts, mActivatedAccounts,
getString(R.string.create_contact), getString(R.string.create),
- prefilledJid, null, fingerprint == null
+ prefilledJid, null, !invite.hasFingerprints()
);
dialog.setOnEnterJidDialogPositiveListener(new EnterJidDialog.OnEnterJidDialogPositiveListener() {
@@ -420,7 +420,7 @@ public class StartConversationActivity extends XmppActivity implements OnRosterU
if (contact.showInRoster()) {
throw new EnterJidDialog.JidError(getString(R.string.contact_already_exists));
} else {
- contact.addOtrFingerprint(fingerprint);
+ //contact.addOtrFingerprint(fingerprint);
xmppConnectionService.createContact(contact);
switchToConversation(contact);
return true;
@@ -842,6 +842,10 @@ 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());
+ }
List<Contact> contacts = xmppConnectionService.findContacts(invite.getJid());
if (invite.isMuc()) {
Conversation muc = xmppConnectionService.findFirstMuc(invite.getJid());
@@ -853,16 +857,19 @@ public class StartConversationActivity extends XmppActivity implements OnRosterU
return false;
}
} else if (contacts.size() == 0) {
- showCreateContactDialog(invite.getJid().toString(), invite.getFingerprint());
+ showCreateContactDialog(invite.getJid().toString(), invite);
return false;
} else if (contacts.size() == 1) {
Contact contact = contacts.get(0);
- if (invite.getFingerprint() != null) {
+ 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 {
diff --git a/src/main/java/eu/siacs/conversations/ui/TrustKeysActivity.java b/src/main/java/eu/siacs/conversations/ui/TrustKeysActivity.java
index 76081a96..26836395 100644
--- a/src/main/java/eu/siacs/conversations/ui/TrustKeysActivity.java
+++ b/src/main/java/eu/siacs/conversations/ui/TrustKeysActivity.java
@@ -18,6 +18,7 @@ import java.util.List;
import java.util.Map;
import java.util.Set;
+import eu.siacs.conversations.Config;
import eu.siacs.conversations.OmemoActivity;
import eu.siacs.conversations.R;
import eu.siacs.conversations.crypto.axolotl.AxolotlService;
@@ -245,7 +246,9 @@ public class TrustKeysActivity extends OmemoActivity implements OnKeyStatusUpdat
Toast.makeText(TrustKeysActivity.this,R.string.error_fetching_omemo_key,Toast.LENGTH_SHORT).show();
break;
case SUCCESS_VERIFIED:
- Toast.makeText(TrustKeysActivity.this,R.string.verified_omemo_key_with_certificate,Toast.LENGTH_LONG).show();
+ Toast.makeText(TrustKeysActivity.this,
+ Config.X509_VERIFICATION ? R.string.verified_omemo_key_with_certificate : R.string.all_omemo_keys_have_been_verified,
+ Toast.LENGTH_LONG).show();
break;
}
}
diff --git a/src/main/java/eu/siacs/conversations/ui/VerifyOTRActivity.java b/src/main/java/eu/siacs/conversations/ui/VerifyOTRActivity.java
index d8d02c12..c065bf9f 100644
--- a/src/main/java/eu/siacs/conversations/ui/VerifyOTRActivity.java
+++ b/src/main/java/eu/siacs/conversations/ui/VerifyOTRActivity.java
@@ -173,11 +173,10 @@ public class VerifyOTRActivity extends XmppActivity implements XmppConnectionSer
protected boolean verifyWithUri(XmppUri uri) {
Contact contact = mConversation.getContact();
- if (this.mConversation.getContact().getJid().equals(uri.getJid()) && uri.getFingerprint() != null) {
- contact.addOtrFingerprint(uri.getFingerprint());
+ if (this.mConversation.getContact().getJid().equals(uri.getJid()) && uri.hasFingerprints()) {
+ xmppConnectionService.verifyFingerprints(contact,uri.getFingerprints());
Toast.makeText(this,R.string.verified,Toast.LENGTH_SHORT).show();
updateView();
- xmppConnectionService.syncRosterToDisk(contact.getAccount());
return true;
} else {
Toast.makeText(this,R.string.could_not_verify_fingerprint,Toast.LENGTH_SHORT).show();
diff --git a/src/main/java/eu/siacs/conversations/utils/XmppUri.java b/src/main/java/eu/siacs/conversations/utils/XmppUri.java
index 15a6c9a1..b2dcc553 100644
--- a/src/main/java/eu/siacs/conversations/utils/XmppUri.java
+++ b/src/main/java/eu/siacs/conversations/utils/XmppUri.java
@@ -4,7 +4,9 @@ import android.net.Uri;
import java.io.UnsupportedEncodingException;
import java.net.URLDecoder;
+import java.util.ArrayList;
import java.util.List;
+import java.util.Locale;
import eu.siacs.conversations.xmpp.jid.InvalidJidException;
import eu.siacs.conversations.xmpp.jid.Jid;
@@ -13,7 +15,9 @@ public class XmppUri {
protected String jid;
protected boolean muc;
- protected String fingerprint;
+ protected List<Fingerprint> fingerprints = new ArrayList<>();
+
+ private static final String OMEMO_URI_PARAM = "omemo-sid-";
public XmppUri(String uri) {
try {
@@ -56,7 +60,7 @@ public class XmppUri {
} else {
jid = uri.getSchemeSpecificPart().split("\\?")[0];
}
- fingerprint = parseFingerprint(uri.getQuery());
+ this.fingerprints = parseFingerprints(uri.getQuery());
} else if ("imto".equalsIgnoreCase(scheme)) {
// sample: imto://xmpp/foo@bar.com
try {
@@ -73,18 +77,28 @@ public class XmppUri {
}
}
- protected String parseFingerprint(String query) {
- if (query == null) {
- return null;
- } else {
- final String NEEDLE = "otr-fingerprint=";
- int index = query.indexOf(NEEDLE);
- if (index >= 0 && query.length() >= (NEEDLE.length() + index + 40)) {
- return query.substring(index + NEEDLE.length(), index + NEEDLE.length() + 40);
- } else {
- return null;
+ protected List<Fingerprint> parseFingerprints(String query) {
+ List<Fingerprint> fingerprints = new ArrayList<>();
+ String[] pairs = query == null ? new String[0] : query.split(";");
+ for(String pair : pairs) {
+ String[] parts = pair.split("=",2);
+ if (parts.length == 2) {
+ String key = parts[0].toLowerCase(Locale.US);
+ String value = parts[1];
+ if ("otr-fingerprint".equals(key)) {
+ fingerprints.add(new Fingerprint(FingerprintType.OTR,value));
+ }
+ if (key.startsWith(OMEMO_URI_PARAM)) {
+ try {
+ int id = Integer.parseInt(key.substring(OMEMO_URI_PARAM.length()));
+ fingerprints.add(new Fingerprint(FingerprintType.OMEMO,value,id));
+ } catch (Exception e) {
+ //ignoring invalid device id
+ }
+ }
}
}
+ return fingerprints;
}
public Jid getJid() {
@@ -95,7 +109,36 @@ public class XmppUri {
}
}
- public String getFingerprint() {
- return this.fingerprint;
+ public List<Fingerprint> getFingerprints() {
+ return this.fingerprints;
+ }
+
+ public boolean hasFingerprints() {
+ return fingerprints.size() > 0;
+ }
+ public enum FingerprintType {
+ OMEMO,
+ OTR
+ }
+
+ public static class Fingerprint {
+ public final FingerprintType type;
+ public final String fingerprint;
+ public final int deviceId;
+
+ public Fingerprint(FingerprintType type, String fingerprint) {
+ this(type, fingerprint, 0);
+ }
+
+ public Fingerprint(FingerprintType type, String fingerprint, int deviceId) {
+ this.type = type;
+ this.fingerprint = fingerprint;
+ this.deviceId = deviceId;
+ }
+
+ @Override
+ public String toString() {
+ return type.toString()+": "+fingerprint+(deviceId != 0 ? " "+String.valueOf(deviceId) : "");
+ }
}
}
diff --git a/src/main/res/values/strings.xml b/src/main/res/values/strings.xml
index f4d4262d..c12b5e96 100644
--- a/src/main/res/values/strings.xml
+++ b/src/main/res/values/strings.xml
@@ -702,4 +702,5 @@
<string name="error_unable_to_create_temporary_file">Unable to create temporary file</string>
<string name="this_device_has_been_verified">This device has been verified</string>
<string name="copy_fingerprint">Copy fingerprint</string>
+ <string name="all_omemo_keys_have_been_verified">All OMEMO keys have been verified</string>
</resources>