show warning dialog beforing verifying keys via a link

This commit is contained in:
Daniel Gultsch 2016-12-03 13:19:56 +01:00
parent 599f7dad2c
commit 6e289b8738
4 changed files with 92 additions and 10 deletions

View File

@ -25,12 +25,10 @@ import android.nfc.NfcAdapter;
import android.os.Build; import android.os.Build;
import android.os.Bundle; import android.os.Bundle;
import android.os.Parcelable; import android.os.Parcelable;
import android.support.v13.app.FragmentPagerAdapter;
import android.support.v4.view.PagerAdapter; import android.support.v4.view.PagerAdapter;
import android.support.v4.view.ViewPager; import android.support.v4.view.ViewPager;
import android.text.Editable; import android.text.Editable;
import android.text.TextWatcher; import android.text.TextWatcher;
import android.util.Log;
import android.util.Pair; import android.util.Pair;
import android.view.ContextMenu; import android.view.ContextMenu;
import android.view.ContextMenu.ContextMenuInfo; import android.view.ContextMenu.ContextMenuInfo;
@ -65,7 +63,6 @@ import java.util.concurrent.atomic.AtomicBoolean;
import eu.siacs.conversations.Config; import eu.siacs.conversations.Config;
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.Blockable;
import eu.siacs.conversations.entities.Bookmark; 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;
@ -788,12 +785,15 @@ public class StartConversationActivity extends XmppActivity implements OnRosterU
if (this.mPendingInvite != null) { if (this.mPendingInvite != null) {
mPendingInvite.invite(); mPendingInvite.invite();
this.mPendingInvite = null; this.mPendingInvite = null;
filter(null);
} else if (!handleIntent(getIntent())) { } else if (!handleIntent(getIntent())) {
if (mSearchEditText != null) { if (mSearchEditText != null) {
filter(mSearchEditText.getText().toString()); filter(mSearchEditText.getText().toString());
} else { } else {
filter(null); filter(null);
} }
} else {
filter(null);
} }
setIntent(null); setIntent(null);
} }
@ -812,15 +812,13 @@ public class StartConversationActivity extends XmppActivity implements OnRosterU
case Intent.ACTION_VIEW: case Intent.ACTION_VIEW:
Uri uri = intent.getData(); Uri uri = intent.getData();
if (uri != null) { if (uri != null) {
Log.d(Config.LOGTAG, "received uri=" + intent.getData()); return new Invite(intent.getData(),false).invite();
return new Invite(intent.getData()).invite();
} else { } else {
return false; return false;
} }
case NfcAdapter.ACTION_NDEF_DISCOVERED: case NfcAdapter.ACTION_NDEF_DISCOVERED:
for (Parcelable message : getIntent().getParcelableArrayExtra(NfcAdapter.EXTRA_NDEF_MESSAGES)) { for (Parcelable message : getIntent().getParcelableArrayExtra(NfcAdapter.EXTRA_NDEF_MESSAGES)) {
if (message instanceof NdefMessage) { if (message instanceof NdefMessage) {
Log.d(Config.LOGTAG, "received message=" + message);
for (NdefRecord record : ((NdefMessage) message).getRecords()) { for (NdefRecord record : ((NdefMessage) message).getRecords()) {
switch (record.getTnf()) { switch (record.getTnf()) {
case NdefRecord.TNF_WELL_KNOWN: case NdefRecord.TNF_WELL_KNOWN:
@ -867,10 +865,14 @@ public class StartConversationActivity extends XmppActivity implements OnRosterU
return false; return false;
} else if (contacts.size() == 1) { } else if (contacts.size() == 1) {
Contact contact = contacts.get(0); Contact contact = contacts.get(0);
if (!invite.isSafeSource() && invite.hasFingerprints()) {
displayVerificationWarningDialog(contact,invite);
} else {
if (invite.hasFingerprints()) { if (invite.hasFingerprints()) {
xmppConnectionService.verifyFingerprints(contact, invite.getFingerprints()); xmppConnectionService.verifyFingerprints(contact, invite.getFingerprints());
} }
switchToConversation(contact, invite.getBody()); switchToConversation(contact, invite.getBody());
}
return true; return true;
} else { } else {
if (mMenuSearchView != null) { if (mMenuSearchView != null) {
@ -885,6 +887,40 @@ public class StartConversationActivity extends XmppActivity implements OnRosterU
} }
} }
private void displayVerificationWarningDialog(final Contact contact, final Invite invite) {
AlertDialog.Builder builder = new AlertDialog.Builder(this);
builder.setTitle(R.string.verify_omemo_keys);
View view = getLayoutInflater().inflate(R.layout.dialog_verify_fingerprints, null);
final CheckBox isTrustedSource = (CheckBox) view.findViewById(R.id.trusted_source);
TextView warning = (TextView) view.findViewById(R.id.warning);
warning.setText(getString(R.string.verifying_omemo_keys_trusted_source,contact.getJid().toBareJid().toString(),contact.getDisplayName()));
builder.setView(view);
builder.setPositiveButton(R.string.confirm, new OnClickListener() {
@Override
public void onClick(DialogInterface dialog, int which) {
if (isTrustedSource.isChecked() && invite.hasFingerprints()) {
xmppConnectionService.verifyFingerprints(contact, invite.getFingerprints());
}
switchToConversation(contact, invite.getBody());
}
});
builder.setNegativeButton(R.string.cancel, new OnClickListener() {
@Override
public void onClick(DialogInterface dialog, int which) {
StartConversationActivity.this.finish();
}
});
AlertDialog dialog = builder.create();
dialog.setCanceledOnTouchOutside(false);
dialog.setOnCancelListener(new DialogInterface.OnCancelListener() {
@Override
public void onCancel(DialogInterface dialog) {
StartConversationActivity.this.finish();
}
});
dialog.show();
}
protected void filter(String needle) { protected void filter(String needle) {
if (xmppConnectionServiceBound) { if (xmppConnectionServiceBound) {
this.filterContacts(needle); this.filterContacts(needle);
@ -1111,6 +1147,10 @@ public class StartConversationActivity extends XmppActivity implements OnRosterU
super(uri); super(uri);
} }
public Invite(Uri uri, boolean safeSource) {
super(uri,safeSource);
}
boolean invite() { boolean invite() {
if (getJid() != null) { if (getJid() != null) {
return handleJid(this); return handleJid(this);

View File

@ -17,6 +17,7 @@ public class XmppUri {
protected boolean muc; protected boolean muc;
protected List<Fingerprint> fingerprints = new ArrayList<>(); protected List<Fingerprint> fingerprints = new ArrayList<>();
private String body; private String body;
protected boolean safeSource = true;
public 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 static final String OTR_URI_PARAM = "otr-fingerprint";
@ -37,6 +38,15 @@ public class XmppUri {
parse(uri); parse(uri);
} }
public XmppUri(Uri uri, boolean safeSource) {
this.safeSource = safeSource;
parse(uri);
}
public boolean isSafeSource() {
return safeSource;
}
protected void parse(Uri uri) { protected void parse(Uri uri) {
String scheme = uri.getScheme(); String scheme = uri.getScheme();
String host = uri.getHost(); String host = uri.getHost();
@ -81,8 +91,12 @@ public class XmppUri {
} }
protected List<Fingerprint> parseFingerprints(String query) { protected List<Fingerprint> parseFingerprints(String query) {
return parseFingerprints(query,';');
}
protected List<Fingerprint> parseFingerprints(String query, char seperator) {
List<Fingerprint> fingerprints = new ArrayList<>(); List<Fingerprint> fingerprints = new ArrayList<>();
String[] pairs = query == null ? new String[0] : query.split(";"); String[] pairs = query == null ? new String[0] : query.split(String.valueOf(seperator));
for(String pair : pairs) { for(String pair : pairs) {
String[] parts = pair.split("=",2); String[] parts = pair.split("=",2);
if (parts.length == 2) { if (parts.length == 2) {

View File

@ -0,0 +1,25 @@
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical"
android:paddingLeft="?attr/dialog_horizontal_padding"
android:paddingRight="?attr/dialog_horizontal_padding"
android:paddingBottom="?attr/dialog_vertical_padding"
android:paddingTop="?attr/dialog_vertical_padding">
<TextView
android:id="@+id/warning"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:textSize="?attr/TextSizeBody"
android:textColor="?attr/color_text_primary"/>
<CheckBox
android:layout_marginTop="8dp"
android:id="@+id/trusted_source"
android:layout_width="wrap_content"
android:textColor="?attr/color_text_primary"
android:layout_height="wrap_content"
android:text="@string/i_followed_this_link_from_a_trusted_source" />
</LinearLayout>

View File

@ -720,4 +720,7 @@
<string name="pref_clean_cache">Clean cache</string> <string name="pref_clean_cache">Clean cache</string>
<string name="pref_clean_private_storage">Clean private storage</string> <string name="pref_clean_private_storage">Clean private storage</string>
<string name="pref_clean_private_storage_summary">Clean private storage where files are kept (They can be re-downloaded from the server)</string> <string name="pref_clean_private_storage_summary">Clean private storage where files are kept (They can be re-downloaded from the server)</string>
<string name="i_followed_this_link_from_a_trusted_source">I followed this link from a trusted source</string>
<string name="verifying_omemo_keys_trusted_source">You are about to verify the OMEMO keys form %1$s after clicking a link. This is only secure if you followed this link from a trusted source where only %2$s could have published this link.</string>
<string name="verify_omemo_keys">Verify OMEMO keys</string>
</resources> </resources>