offer verification directly from the trust keys screen

Daniel Gultsch created

Change summary

src/main/java/eu/siacs/conversations/services/XmppConnectionService.java |  8 
src/main/java/eu/siacs/conversations/ui/TrustKeysActivity.java           | 73 
src/main/res/drawable-hdpi/ic_action_camera.png                          |  0 
src/main/res/drawable-hdpi/ic_camera_alt_white_24dp.png                  |  0 
src/main/res/drawable-mdpi/ic_action_camera.png                          |  0 
src/main/res/drawable-mdpi/ic_camera_alt_white_24dp.png                  |  0 
src/main/res/drawable-xhdpi/ic_action_camera.png                         |  0 
src/main/res/drawable-xhdpi/ic_camera_alt_white_24dp.png                 |  0 
src/main/res/drawable-xxhdpi/ic_action_camera.png                        |  0 
src/main/res/drawable-xxhdpi/ic_camera_alt_white_24dp.png                |  0 
src/main/res/drawable-xxxhdpi/ic_camera_alt_white_24dp.png               |  0 
src/main/res/menu/trust_keys.xml                                         |  9 
src/main/res/values-v21/themes.xml                                       |  2 
src/main/res/values/attrs.xml                                            |  1 
src/main/res/values/strings.xml                                          |  4 
src/main/res/values/themes.xml                                           |  2 
16 files changed, 96 insertions(+), 3 deletions(-)

Detailed changes

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

@@ -3617,17 +3617,20 @@ public class XmppConnectionService extends Service {
 		});
 	}
 
-	public void verifyFingerprints(Contact contact, List<XmppUri.Fingerprint> fingerprints) {
+	public boolean verifyFingerprints(Contact contact, List<XmppUri.Fingerprint> fingerprints) {
 		boolean needsRosterWrite = false;
+		boolean performedVerification = false;
 		final AxolotlService axolotlService = contact.getAccount().getAxolotlService();
 		for(XmppUri.Fingerprint fp : fingerprints) {
 			if (fp.type == XmppUri.FingerprintType.OTR) {
-				needsRosterWrite |= contact.addOtrFingerprint(fp.fingerprint);
+				performedVerification |= contact.addOtrFingerprint(fp.fingerprint);
+				needsRosterWrite |= performedVerification;
 			} 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()) {
+						performedVerification = true;
 						axolotlService.setFingerprintTrust(fingerprint,fingerprintStatus.toVerified());
 					}
 				} else {
@@ -3638,6 +3641,7 @@ public class XmppConnectionService extends Service {
 		if (needsRosterWrite) {
 			syncRosterToDisk(contact.getAccount());
 		}
+		return performedVerification;
 	}
 
 	public boolean verifyFingerprints(Account account, List<XmppUri.Fingerprint> fingerprints) {

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

@@ -1,7 +1,12 @@
 package eu.siacs.conversations.ui;
 
+import android.app.ActionBar;
 import android.content.Intent;
 import android.os.Bundle;
+import android.util.Log;
+import android.view.Gravity;
+import android.view.Menu;
+import android.view.MenuItem;
 import android.view.View;
 import android.view.View.OnClickListener;
 import android.widget.Button;
@@ -10,6 +15,9 @@ import android.widget.LinearLayout;
 import android.widget.TextView;
 import android.widget.Toast;
 
+import com.google.zxing.integration.android.IntentIntegrator;
+import com.google.zxing.integration.android.IntentResult;
+
 import org.whispersystems.libaxolotl.IdentityKey;
 
 import java.util.ArrayList;
@@ -23,9 +31,9 @@ import eu.siacs.conversations.OmemoActivity;
 import eu.siacs.conversations.R;
 import eu.siacs.conversations.crypto.axolotl.AxolotlService;
 import eu.siacs.conversations.crypto.axolotl.FingerprintStatus;
-import eu.siacs.conversations.crypto.axolotl.XmppAxolotlSession;
 import eu.siacs.conversations.entities.Account;
 import eu.siacs.conversations.entities.Conversation;
+import eu.siacs.conversations.utils.XmppUri;
 import eu.siacs.conversations.xmpp.OnKeyStatusUpdated;
 import eu.siacs.conversations.xmpp.jid.InvalidJidException;
 import eu.siacs.conversations.xmpp.jid.Jid;
@@ -64,6 +72,7 @@ public class TrustKeysActivity extends OmemoActivity implements OnKeyStatusUpdat
 			finish();
 		}
 	};
+	private XmppUri mPendingFingerprintVerificationUri = null;
 
 	@Override
 	protected void refreshUiReal() {
@@ -102,6 +111,64 @@ public class TrustKeysActivity extends OmemoActivity implements OnKeyStatusUpdat
 		}
 	}
 
+	@Override
+	public boolean onCreateOptionsMenu(Menu menu) {
+		getMenuInflater().inflate(R.menu.trust_keys, menu);
+		Toast toast = Toast.makeText(this,R.string.use_camera_icon_to_scan_barcode,Toast.LENGTH_LONG);
+		ActionBar actionBar = getActionBar();
+		toast.setGravity(Gravity.TOP | Gravity.END, 0 ,actionBar == null ? 0 : actionBar.getHeight());
+		toast.show();
+		return super.onCreateOptionsMenu(menu);
+	}
+
+	@Override
+	public boolean onOptionsItemSelected(MenuItem item) {
+		switch (item.getItemId()) {
+			case R.id.action_scan_qr_code:
+				if (hasPendingKeyFetches()) {
+					Toast.makeText(this, R.string.please_wait_for_keys_to_be_fetched, Toast.LENGTH_SHORT).show();
+				} else {
+					new IntentIntegrator(this).initiateScan();
+					return true;
+				}
+		}
+		return super.onOptionsItemSelected(item);
+	}
+
+	@Override
+	public void onActivityResult(int requestCode, int resultCode, Intent intent) {
+		IntentResult scanResult = IntentIntegrator.parseActivityResult(requestCode, resultCode, intent);
+		if (scanResult != null && scanResult.getFormatName() != null) {
+			String data = scanResult.getContents();
+			XmppUri uri = new XmppUri(data);
+			if (xmppConnectionServiceBound) {
+				processFingerprintVerification(uri);
+				populateView();
+			} else {
+				this.mPendingFingerprintVerificationUri =uri;
+			}
+		}
+	}
+
+	private void processFingerprintVerification(XmppUri uri) {
+		if (mConversation != null
+				&& mAccount != null
+				&& uri.hasFingerprints()
+				&& mAccount.getAxolotlService().getCryptoTargets(mConversation).contains(uri.getJid())) {
+			boolean performedVerification = xmppConnectionService.verifyFingerprints(mAccount.getRoster().getContact(uri.getJid()),uri.getFingerprints());
+			boolean keys = reloadFingerprints();
+			if (performedVerification && !keys && !hasNoOtherTrustedKeys() && !hasPendingKeyFetches()) {
+				Toast.makeText(this,R.string.all_omemo_keys_have_been_verified, Toast.LENGTH_SHORT).show();
+				finishOk();
+			} else if (performedVerification) {
+				Toast.makeText(this,R.string.verified_fingerprints,Toast.LENGTH_SHORT).show();
+			}
+		} else {
+			Log.d(Config.LOGTAG,"xmpp uri was: "+uri.getJid()+" has Fingerprints: "+Boolean.toString(uri.hasFingerprints()));
+			Toast.makeText(this,R.string.barcode_does_not_contain_fingerprints_for_this_conversation,Toast.LENGTH_SHORT).show();
+		}
+	}
+
 	private void populateView() {
 		setTitle(getString(R.string.trust_omemo_fingerprints));
 		ownKeys.removeAllViews();
@@ -216,6 +283,10 @@ public class TrustKeysActivity extends OmemoActivity implements OnKeyStatusUpdat
 		if (this.mAccount != null && intent != null) {
 			String uuid = intent.getStringExtra("conversation");
 			this.mConversation = xmppConnectionService.findConversationByUuid(uuid);
+			if (this.mPendingFingerprintVerificationUri != null) {
+				processFingerprintVerification(this.mPendingFingerprintVerificationUri);
+				this.mPendingFingerprintVerificationUri = null;
+			}
 			reloadFingerprints();
 			populateView();
 		}

src/main/res/menu/trust_keys.xml 🔗

@@ -0,0 +1,9 @@
+<?xml version="1.0" encoding="utf-8"?>
+<menu xmlns:android="http://schemas.android.com/apk/res/android">
+
+	<item
+		android:id="@+id/action_scan_qr_code"
+		android:title="@string/scan_qr_code"
+		android:showAsAction="always"
+		android:icon="?attr/icon_scan_qr_code"/>
+</menu>

src/main/res/values-v21/themes.xml 🔗

@@ -60,6 +60,7 @@
         <item name="attr/icon_settings">@drawable/ic_settings_black_24dp</item>
         <item name="attr/icon_import_export">@drawable/ic_import_export_white_24dp</item>
         <item name="attr/icon_share">@drawable/ic_share_white_24dp</item>
+        <item name="attr/icon_scan_qr_code">@drawable/ic_camera_alt_white_24dp</item>
 
         <item name="attr/icon_notifications">@drawable/ic_notifications_black54_24dp</item>
         <item name="attr/icon_notifications_off">@drawable/ic_notifications_off_black54_24dp</item>
@@ -126,6 +127,7 @@
         <item name="attr/icon_settings">@drawable/ic_settings_white_24dp</item>
         <item name="attr/icon_import_export">@drawable/ic_import_export_white_24dp</item>
         <item name="attr/icon_share">@drawable/ic_share_white_24dp</item>
+        <item name="attr/icon_scan_qr_code">@drawable/ic_camera_alt_white_24dp</item>
 
         <item name="attr/icon_notifications">@drawable/ic_notifications_white_24dp</item>
         <item name="attr/icon_notifications_off">@drawable/ic_notifications_off_white_24dp</item>

src/main/res/values/attrs.xml 🔗

@@ -47,6 +47,7 @@
     <attr name="icon_settings" format="reference"/>
     <attr name="icon_share" format="reference"/>
     <attr name="icon_import_export" format="reference"/>
+    <attr name="icon_scan_qr_code" format="reference"/>
 
     <attr name="icon_notifications" format="reference"/>
     <attr name="icon_notifications_off" format="reference"/>

src/main/res/values/strings.xml 🔗

@@ -703,4 +703,8 @@
 	<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>
+	<string name="barcode_does_not_contain_fingerprints_for_this_conversation">Barcode does not contain fingerprints for this conversation.</string>
+	<string name="verified_fingerprints">Verified fingerprints</string>
+	<string name="use_camera_icon_to_scan_barcode">Use the camera to scan a contacts barcode</string>
+	<string name="please_wait_for_keys_to_be_fetched">Please wait for keys to be fetched</string>
 </resources>

src/main/res/values/themes.xml 🔗

@@ -57,6 +57,7 @@
         <item name="attr/icon_settings">@drawable/ic_action_settings</item>
         <item name="attr/icon_import_export">@drawable/ic_stat_communication_import_export</item>
         <item name="attr/icon_share">@drawable/ic_action_share</item>
+        <item name="attr/icon_scan_qr_code">@drawable/ic_action_camera</item>
 
         <item name="attr/icon_notifications">@drawable/ic_notifications_black54_24dp</item>
         <item name="attr/icon_notifications_off">@drawable/ic_notifications_off_black54_24dp</item>
@@ -120,6 +121,7 @@
         <item name="attr/icon_settings">@drawable/ic_action_settings_white</item>
         <item name="attr/icon_import_export">@drawable/ic_stat_communication_import_export</item>
         <item name="attr/icon_share">@drawable/ic_action_share</item>
+        <item name="attr/icon_scan_qr_code">@drawable/ic_action_camera</item>
 
         <item name="attr/icon_notifications">@drawable/ic_notifications_white80</item>
         <item name="attr/icon_notifications_off">@drawable/ic_notifications_off_white80</item>