parse omemo fingerprints from uris
This commit is contained in:
		
							parent
							
								
									3f3b360eee
								
							
						
					
					
						commit
						7e2e42cb11
					
				| @ -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) { | ||||
|  | ||||
| @ -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, | ||||
|  | ||||
| @ -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()); | ||||
| 	} | ||||
| } | ||||
|  | ||||
| @ -73,7 +73,7 @@ public class XmppAxolotlSession { | ||||
| 	} | ||||
| 
 | ||||
| 	protected void setTrust(FingerprintStatus status) { | ||||
| 		sqLiteAxolotlStore.setFingerprintTrust(getFingerprint(), status); | ||||
| 		sqLiteAxolotlStore.setFingerprintStatus(getFingerprint(), status); | ||||
| 	} | ||||
| 
 | ||||
| 	protected FingerprintStatus getTrust() { | ||||
|  | ||||
| @ -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) { | ||||
|  | ||||
| @ -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(); | ||||
|  | ||||
| @ -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 { | ||||
|  | ||||
| @ -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; | ||||
| 					} | ||||
| 				} | ||||
|  | ||||
| @ -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(); | ||||
|  | ||||
| @ -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,19 +77,29 @@ 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() { | ||||
| 		try { | ||||
| @ -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) : ""); | ||||
| 		} | ||||
| 	} | ||||
| } | ||||
|  | ||||
| @ -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> | ||||
|  | ||||
		Loading…
	
		Reference in New Issue
	
	Block a user
	 Daniel Gultsch
						Daniel Gultsch