made scan and show qr code more accessible in VerifyOtrActivity

This commit is contained in:
iNPUTmice 2014-11-16 02:10:29 +01:00
parent 2b21bc13fc
commit 2067b9bd8d
6 changed files with 214 additions and 58 deletions

View file

@ -45,8 +45,6 @@ import android.widget.Spinner;
import com.google.zxing.integration.android.IntentIntegrator; import com.google.zxing.integration.android.IntentIntegrator;
import com.google.zxing.integration.android.IntentResult; import com.google.zxing.integration.android.IntentResult;
import java.io.UnsupportedEncodingException;
import java.net.URLDecoder;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Arrays; import java.util.Arrays;
import java.util.Collections; import java.util.Collections;
@ -59,10 +57,10 @@ import eu.siacs.conversations.entities.Bookmark;
import eu.siacs.conversations.entities.Contact; import eu.siacs.conversations.entities.Contact;
import eu.siacs.conversations.entities.Conversation; import eu.siacs.conversations.entities.Conversation;
import eu.siacs.conversations.entities.ListItem; import eu.siacs.conversations.entities.ListItem;
import eu.siacs.conversations.utils.XmppUri;
import eu.siacs.conversations.services.XmppConnectionService.OnRosterUpdate; import eu.siacs.conversations.services.XmppConnectionService.OnRosterUpdate;
import eu.siacs.conversations.ui.adapter.KnownHostsAdapter; import eu.siacs.conversations.ui.adapter.KnownHostsAdapter;
import eu.siacs.conversations.ui.adapter.ListItemAdapter; import eu.siacs.conversations.ui.adapter.ListItemAdapter;
import eu.siacs.conversations.utils.CryptoHelper;
import eu.siacs.conversations.utils.Validator; import eu.siacs.conversations.utils.Validator;
import eu.siacs.conversations.xmpp.jid.InvalidJidException; import eu.siacs.conversations.xmpp.jid.InvalidJidException;
import eu.siacs.conversations.xmpp.jid.Jid; import eu.siacs.conversations.xmpp.jid.Jid;
@ -755,21 +753,17 @@ public class StartConversationActivity extends XmppActivity implements OnRosterU
} }
} }
private class Invite { private class Invite extends XmppUri {
private String jid; private String jid;
private boolean muc; private boolean muc;
private String fingerprint; private String fingerprint;
Invite(Uri uri) { public Invite(Uri uri) {
parse(uri); super(uri);
} }
Invite(String uri) { public Invite(String uri) {
try { super(uri);
parse(Uri.parse(uri));
} catch (IllegalArgumentException e) {
jid = null;
}
} }
boolean invite() { boolean invite() {
@ -782,39 +776,5 @@ public class StartConversationActivity extends XmppActivity implements OnRosterU
} }
return false; return false;
} }
void parse(Uri uri) {
String scheme = uri.getScheme();
if ("xmpp".equals(scheme)) {
// sample: xmpp:jid@foo.com
muc = "join".equalsIgnoreCase(uri.getQuery());
if (uri.getAuthority() != null) {
jid = uri.getAuthority();
} else {
jid = uri.getSchemeSpecificPart().split("\\?")[0];
}
fingerprint = parseFingerprint(uri.getQuery());
} else if ("imto".equals(scheme)) {
// sample: imto://xmpp/jid@foo.com
try {
jid = URLDecoder.decode(uri.getEncodedPath(), "UTF-8").split("/")[1];
} catch (final UnsupportedEncodingException ignored) {
}
}
}
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 CryptoHelper.prettifyFingerprint(query.substring(index + NEEDLE.length(), index + NEEDLE.length() + 40));
} else {
return null;
}
}
}
} }
} }

View file

@ -1,7 +1,11 @@
package eu.siacs.conversations.ui; package eu.siacs.conversations.ui;
import android.app.AlertDialog;
import android.content.DialogInterface;
import android.content.Intent; import android.content.Intent;
import android.os.Bundle; import android.os.Bundle;
import android.view.Menu;
import android.view.MenuItem;
import android.view.View; import android.view.View;
import android.widget.Button; import android.widget.Button;
import android.widget.EditText; import android.widget.EditText;
@ -9,14 +13,19 @@ import android.widget.RelativeLayout;
import android.widget.TextView; import android.widget.TextView;
import android.widget.Toast; import android.widget.Toast;
import com.google.zxing.integration.android.IntentIntegrator;
import com.google.zxing.integration.android.IntentResult;
import net.java.otr4j.OtrException; import net.java.otr4j.OtrException;
import net.java.otr4j.session.Session; import net.java.otr4j.session.Session;
import eu.siacs.conversations.R; import eu.siacs.conversations.R;
import eu.siacs.conversations.entities.Account; import eu.siacs.conversations.entities.Account;
import eu.siacs.conversations.entities.Contact;
import eu.siacs.conversations.entities.Conversation; import eu.siacs.conversations.entities.Conversation;
import eu.siacs.conversations.services.XmppConnectionService; import eu.siacs.conversations.services.XmppConnectionService;
import eu.siacs.conversations.utils.CryptoHelper; import eu.siacs.conversations.utils.CryptoHelper;
import eu.siacs.conversations.utils.XmppUri;
import eu.siacs.conversations.xmpp.jid.InvalidJidException; import eu.siacs.conversations.xmpp.jid.InvalidJidException;
import eu.siacs.conversations.xmpp.jid.Jid; import eu.siacs.conversations.xmpp.jid.Jid;
@ -32,20 +41,38 @@ public class VerifyOTRActivity extends XmppActivity implements XmppConnectionSer
private TextView mYourFingerprint; private TextView mYourFingerprint;
private EditText mSharedSecretHint; private EditText mSharedSecretHint;
private EditText mSharedSecretSecret; private EditText mSharedSecretSecret;
private Button mButtonVerifyFingerprint; private Button mButtonScanQrCode;
private Button mButtonShowQrCode;
private Button mButtonSharedSecretPositive; private Button mButtonSharedSecretPositive;
private Button mButtonSharedSecretNegative; private Button mButtonSharedSecretNegative;
private TextView mStatusMessage; private TextView mStatusMessage;
private Account mAccount; private Account mAccount;
private Conversation mConversation; private Conversation mConversation;
private View.OnClickListener mVerifyFingerprintListener = new View.OnClickListener() { private DialogInterface.OnClickListener mVerifyFingerprintListener = new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialogInterface, int click) {
mConversation.verifyOtrFingerprint();
updateView();
xmppConnectionService.syncRosterToDisk(mConversation.getAccount());
}
};
private View.OnClickListener mShowQrCodeListener = new View.OnClickListener() {
@Override
public void onClick(final View view) {
showQrCode();
}
};
private View.OnClickListener mScanQrCodeListener = new View.OnClickListener() {
@Override @Override
public void onClick(View view) { public void onClick(View view) {
mConversation.verifyOtrFingerprint(); new IntentIntegrator(VerifyOTRActivity.this).initiateScan();
finish();
} }
}; };
private View.OnClickListener mCreateSharedSecretListener = new View.OnClickListener() { private View.OnClickListener mCreateSharedSecretListener = new View.OnClickListener() {
@ -97,6 +124,8 @@ public class VerifyOTRActivity extends XmppActivity implements XmppConnectionSer
} }
}; };
private XmppUri mPendingUri = null;
protected boolean initSmp(final String question, final String secret) { protected boolean initSmp(final String question, final String secret) {
final Session session = mConversation.getOtrSession(); final Session session = mConversation.getOtrSession();
if (session!=null) { if (session!=null) {
@ -143,6 +172,18 @@ public class VerifyOTRActivity extends XmppActivity implements XmppConnectionSer
} }
} }
protected void verifyWithUri(XmppUri uri) {
Contact contact = mConversation.getContact();
if (this.mConversation.getContact().getJid().equals(uri.getJid()) && uri.getFingerprint() != null) {
contact.addOtrFingerprint(uri.getFingerprint());
Toast.makeText(this,R.string.verified,Toast.LENGTH_SHORT).show();
updateView();
xmppConnectionService.syncRosterToDisk(contact.getAccount());
} else {
Toast.makeText(this,R.string.could_not_verify_fingerprint,Toast.LENGTH_SHORT).show();
}
}
protected boolean isAccountOnline() { protected boolean isAccountOnline() {
if (this.mAccount.getStatus() != Account.State.ONLINE) { if (this.mAccount.getStatus() != Account.State.ONLINE) {
Toast.makeText(this,R.string.not_connected_try_again,Toast.LENGTH_SHORT).show(); Toast.makeText(this,R.string.not_connected_try_again,Toast.LENGTH_SHORT).show();
@ -173,15 +214,37 @@ public class VerifyOTRActivity extends XmppActivity implements XmppConnectionSer
} }
} }
@Override
public void onActivityResult(int requestCode, int resultCode, Intent intent) {
if ((requestCode & 0xFFFF) == IntentIntegrator.REQUEST_CODE) {
IntentResult scanResult = IntentIntegrator.parseActivityResult(requestCode, resultCode, intent);
if (scanResult != null && scanResult.getFormatName() != null) {
String data = scanResult.getContents();
XmppUri uri = new XmppUri(data);
if (xmppConnectionServiceBound) {
verifyWithUri(uri);
} else {
this.mPendingUri = uri;
}
}
}
super.onActivityResult(requestCode, requestCode, intent);
}
@Override @Override
protected void onBackendConnected() { protected void onBackendConnected() {
if (handleIntent(getIntent())) { if (handleIntent(getIntent())) {
if (mPendingUri!=null) {
verifyWithUri(mPendingUri);
mPendingUri = null;
}
updateView(); updateView();
} }
} }
protected void updateView() { protected void updateView() {
if (this.mConversation.hasValidOtrSession()) { if (this.mConversation.hasValidOtrSession()) {
invalidateOptionsMenu();
this.mVerificationAreaOne.setVisibility(View.VISIBLE); this.mVerificationAreaOne.setVisibility(View.VISIBLE);
this.mVerificationAreaTwo.setVisibility(View.VISIBLE); this.mVerificationAreaTwo.setVisibility(View.VISIBLE);
this.mErrorNoSession.setVisibility(View.GONE); this.mErrorNoSession.setVisibility(View.GONE);
@ -191,9 +254,9 @@ public class VerifyOTRActivity extends XmppActivity implements XmppConnectionSer
Conversation.Smp smp = mConversation.smp(); Conversation.Smp smp = mConversation.smp();
Session session = mConversation.getOtrSession(); Session session = mConversation.getOtrSession();
if (mConversation.isOtrFingerprintVerified()) { if (mConversation.isOtrFingerprintVerified()) {
deactivateButton(mButtonVerifyFingerprint, R.string.verified); deactivateButton(mButtonScanQrCode, R.string.verified);
} else { } else {
activateButton(mButtonVerifyFingerprint, R.string.verify, mVerifyFingerprintListener); activateButton(mButtonScanQrCode, R.string.scan_qr_code, mScanQrCodeListener);
} }
if (smp.status == Conversation.Smp.STATUS_NONE) { if (smp.status == Conversation.Smp.STATUS_NONE) {
activateButton(mButtonSharedSecretPositive, R.string.create, mCreateSharedSecretListener); activateButton(mButtonSharedSecretPositive, R.string.create, mCreateSharedSecretListener);
@ -268,7 +331,9 @@ public class VerifyOTRActivity extends XmppActivity implements XmppConnectionSer
this.mYourFingerprint = (TextView) findViewById(R.id.your_fingerprint); this.mYourFingerprint = (TextView) findViewById(R.id.your_fingerprint);
this.mButtonSharedSecretNegative = (Button) findViewById(R.id.button_shared_secret_negative); this.mButtonSharedSecretNegative = (Button) findViewById(R.id.button_shared_secret_negative);
this.mButtonSharedSecretPositive = (Button) findViewById(R.id.button_shared_secret_positive); this.mButtonSharedSecretPositive = (Button) findViewById(R.id.button_shared_secret_positive);
this.mButtonVerifyFingerprint = (Button) findViewById(R.id.button_verify_fingerprint); this.mButtonScanQrCode = (Button) findViewById(R.id.button_scan_qr_code);
this.mButtonShowQrCode = (Button) findViewById(R.id.button_show_qr_code);
this.mButtonShowQrCode.setOnClickListener(this.mShowQrCodeListener);
this.mSharedSecretSecret = (EditText) findViewById(R.id.shared_secret_secret); this.mSharedSecretSecret = (EditText) findViewById(R.id.shared_secret_secret);
this.mSharedSecretHint = (EditText) findViewById(R.id.shared_secret_hint); this.mSharedSecretHint = (EditText) findViewById(R.id.shared_secret_hint);
this.mStatusMessage= (TextView) findViewById(R.id.status_message); this.mStatusMessage= (TextView) findViewById(R.id.status_message);
@ -277,6 +342,35 @@ public class VerifyOTRActivity extends XmppActivity implements XmppConnectionSer
this.mErrorNoSession = (TextView) findViewById(R.id.error_no_session); this.mErrorNoSession = (TextView) findViewById(R.id.error_no_session);
} }
@Override
public boolean onCreateOptionsMenu(Menu menu) {
getMenuInflater().inflate(R.menu.verify_otr, menu);
if (mConversation != null && mConversation.isOtrFingerprintVerified()) {
MenuItem manuallyVerifyItem = menu.findItem(R.id.manually_verify);
manuallyVerifyItem.setVisible(false);
}
return true;
}
@Override
public boolean onOptionsItemSelected(MenuItem menuItem) {
if (menuItem.getItemId() == R.id.manually_verify) {
showManuallyVerifyDialog();
return true;
} else {
return super.onOptionsItemSelected(menuItem);
}
}
private void showManuallyVerifyDialog() {
AlertDialog.Builder builder = new AlertDialog.Builder(this);
builder.setTitle(R.string.manually_verify);
builder.setMessage(R.string.are_you_sure_verify_fingerprint);
builder.setNegativeButton(R.string.cancel, null);
builder.setPositiveButton(R.string.verify, mVerifyFingerprintListener);
builder.create().show();
}
@Override @Override
protected String getShareableUri() { protected String getShareableUri() {
if (mAccount!=null) { if (mAccount!=null) {

View file

@ -0,0 +1,79 @@
package eu.siacs.conversations.utils;
import android.net.Uri;
import java.io.UnsupportedEncodingException;
import java.net.URLDecoder;
import eu.siacs.conversations.utils.CryptoHelper;
import eu.siacs.conversations.xmpp.jid.InvalidJidException;
import eu.siacs.conversations.xmpp.jid.Jid;
public class XmppUri {
private String jid;
private boolean muc;
private String fingerprint;
public XmppUri(String uri) {
try {
parse(Uri.parse(uri));
} catch (IllegalArgumentException e) {
jid = null;
}
}
public XmppUri(Uri uri) {
parse(uri);
}
protected void parse(Uri uri) {
String scheme = uri.getScheme();
if ("xmpp".equals(scheme)) {
// sample: xmpp:jid@foo.com
muc = "join".equalsIgnoreCase(uri.getQuery());
if (uri.getAuthority() != null) {
jid = uri.getAuthority();
} else {
jid = uri.getSchemeSpecificPart().split("\\?")[0];
}
fingerprint = parseFingerprint(uri.getQuery());
} else if ("imto".equals(scheme)) {
// sample: imto://xmpp/jid@foo.com
try {
jid = URLDecoder.decode(uri.getEncodedPath(), "UTF-8").split("/")[1];
} catch (final UnsupportedEncodingException ignored) {
}
}
}
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 CryptoHelper.prettifyFingerprint(query.substring(index + NEEDLE.length(), index + NEEDLE.length() + 40));
} else {
return null;
}
}
}
public Jid getJid() {
try {
return Jid.fromString(this.jid);
} catch (InvalidJidException e) {
return null;
}
}
public String getFingerprint() {
return this.fingerprint;
}
public boolean isMuc() {
return this.muc;
}
}

View file

@ -76,27 +76,27 @@
android:layout_alignParentRight="true" > android:layout_alignParentRight="true" >
<Button <Button
android:id="@+id/button_show_qr_code"
style="?android:attr/borderlessButtonStyle" style="?android:attr/borderlessButtonStyle"
android:layout_width="0dp" android:layout_width="0dp"
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:layout_weight="1" android:layout_weight="1"
android:visibility="invisible" /> android:text="@string/show_qr_code"/>
<View <View
android:layout_width="1dp" android:layout_width="1dp"
android:layout_height="fill_parent" android:layout_height="fill_parent"
android:layout_marginBottom="7dp" android:layout_marginBottom="7dp"
android:layout_marginTop="7dp" android:layout_marginTop="7dp"
android:background="@color/divider" android:background="@color/divider" />
android:visibility="invisible"/>
<Button <Button
android:id="@+id/button_verify_fingerprint" android:id="@+id/button_scan_qr_code"
style="?android:attr/borderlessButtonStyle" style="?android:attr/borderlessButtonStyle"
android:layout_width="0dp" android:layout_width="0dp"
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:layout_weight="1" android:layout_weight="1"
android:text="@string/verify" android:text="@string/scan_qr_code"
android:textColor="@color/primarytext" /> android:textColor="@color/primarytext" />
</LinearLayout> </LinearLayout>
</RelativeLayout> </RelativeLayout>

View file

@ -0,0 +1,20 @@
<?xml version="1.0" encoding="utf-8"?>
<menu xmlns:android="http://schemas.android.com/apk/res/android">
<item
android:id="@+id/manually_verify"
android:orderInCategory="10"
android:showAsAction="never"
android:title="@string/manually_verify" />
<item
android:id="@+id/action_accounts"
android:orderInCategory="90"
android:showAsAction="never"
android:title="@string/action_accounts" />
<item
android:id="@+id/action_settings"
android:orderInCategory="100"
android:showAsAction="never"
android:title="@string/action_settings" />
</menu>

View file

@ -346,4 +346,7 @@
<string name="file_transmission_failed">file transmission failed</string> <string name="file_transmission_failed">file transmission failed</string>
<string name="file_deleted">The file has been deleted</string> <string name="file_deleted">The file has been deleted</string>
<string name="no_application_found_to_open_file">No application found to open file</string> <string name="no_application_found_to_open_file">No application found to open file</string>
<string name="could_not_verify_fingerprint">Could not verify fingerprint</string>
<string name="manually_verify">Manually verify</string>
<string name="are_you_sure_verify_fingerprint">Are you sure that you want to verify your contacts OTR fingerprint?</string>
</resources> </resources>