From 198dc2c6b444671ec71deb10fbbaaced6e03dced Mon Sep 17 00:00:00 2001 From: Daniel Gultsch Date: Tue, 1 Mar 2016 11:26:59 +0100 Subject: [PATCH] let users confirm each member in a conference even if that contact is already trusted --- .../crypto/axolotl/AxolotlService.java | 2 +- .../conversations/entities/Conversation.java | 72 ++++++++++++++++--- .../ui/ConversationActivity.java | 4 +- .../conversations/ui/TrustKeysActivity.java | 50 +++++++++---- src/main/res/layout/keys_card.xml | 60 +++++++++------- src/main/res/values/strings.xml | 1 + 6 files changed, 137 insertions(+), 52 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 8658dfe20..cc5c2491b 100644 --- a/src/main/java/eu/siacs/conversations/crypto/axolotl/AxolotlService.java +++ b/src/main/java/eu/siacs/conversations/crypto/axolotl/AxolotlService.java @@ -284,7 +284,7 @@ public class AxolotlService implements OnAdvancedStreamFeaturesLoaded { private Set findSessionsForConversation(Conversation conversation) { HashSet sessions = new HashSet<>(); - for(Jid jid : getCryptoTargets(conversation)) { + for(Jid jid : conversation.getAcceptedCryptoTargets()) { sessions.addAll(this.sessions.getAll(getAddressForJid(jid)).values()); } return sessions; diff --git a/src/main/java/eu/siacs/conversations/entities/Conversation.java b/src/main/java/eu/siacs/conversations/entities/Conversation.java index f05b3f911..0252ea749 100644 --- a/src/main/java/eu/siacs/conversations/entities/Conversation.java +++ b/src/main/java/eu/siacs/conversations/entities/Conversation.java @@ -9,11 +9,13 @@ import net.java.otr4j.session.SessionID; import net.java.otr4j.session.SessionImpl; import net.java.otr4j.session.SessionStatus; +import org.json.JSONArray; import org.json.JSONException; import org.json.JSONObject; import java.security.interfaces.DSAPublicKey; import java.util.ArrayList; +import java.util.Arrays; import java.util.Collections; import java.util.Comparator; import java.util.Iterator; @@ -48,6 +50,7 @@ public class Conversation extends AbstractEntity implements Blockable { public static final String ATTRIBUTE_MUC_PASSWORD = "muc_password"; public static final String ATTRIBUTE_MUTED_TILL = "muted_till"; public static final String ATTRIBUTE_ALWAYS_NOTIFY = "always_notify"; + public static final String ATTRIBUTE_CRYPTO_TARGETS = "crypto_targets"; private String name; private String contactUuid; @@ -313,6 +316,18 @@ public class Conversation extends AbstractEntity implements Blockable { return getLongAttribute("last_clear_history", 0); } + public List getAcceptedCryptoTargets() { + if (mode == MODE_SINGLE) { + return Arrays.asList(getJid().toBareJid()); + } else { + return getJidListAttribute(ATTRIBUTE_CRYPTO_TARGETS); + } + } + + public void setAcceptedCryptoTargets(List acceptedTargets) { + setAttribute(ATTRIBUTE_CRYPTO_TARGETS, acceptedTargets); + } + public void setCorrectingMessage(Message correctingMessage) { this.correctingMessage = correctingMessage; } @@ -794,22 +809,61 @@ public class Conversation extends AbstractEntity implements Blockable { } public boolean setAttribute(String key, String value) { - try { - this.attributes.put(key, value); - return true; - } catch (JSONException e) { - return false; + synchronized (this.attributes) { + try { + this.attributes.put(key, value); + return true; + } catch (JSONException e) { + return false; + } + } + } + + public boolean setAttribute(String key, List jids) { + JSONArray array = new JSONArray(); + for(Jid jid : jids) { + array.put(jid.toBareJid().toString()); + } + synchronized (this.attributes) { + try { + this.attributes.put(key, array); + return true; + } catch (JSONException e) { + e.printStackTrace(); + return false; + } } } public String getAttribute(String key) { - try { - return this.attributes.getString(key); - } catch (JSONException e) { - return null; + synchronized (this.attributes) { + try { + return this.attributes.getString(key); + } catch (JSONException e) { + return null; + } } } + public List getJidListAttribute(String key) { + ArrayList list = new ArrayList<>(); + synchronized (this.attributes) { + try { + JSONArray array = this.attributes.getJSONArray(key); + for (int i = 0; i < array.length(); ++i) { + try { + list.add(Jid.fromString(array.getString(i))); + } catch (InvalidJidException e) { + //ignored + } + } + } catch (JSONException e) { + //ignored + } + } + return list; + } + public int getIntAttribute(String key, int defaultValue) { String value = this.getAttribute(key); if (value == null) { diff --git a/src/main/java/eu/siacs/conversations/ui/ConversationActivity.java b/src/main/java/eu/siacs/conversations/ui/ConversationActivity.java index e4ffb3e46..eac531242 100644 --- a/src/main/java/eu/siacs/conversations/ui/ConversationActivity.java +++ b/src/main/java/eu/siacs/conversations/ui/ConversationActivity.java @@ -1531,11 +1531,12 @@ public class ConversationActivity extends XmppActivity protected boolean trustKeysIfNeeded(int requestCode, int attachmentChoice) { AxolotlService axolotlService = mSelectedConversation.getAccount().getAxolotlService(); final List targets = axolotlService.getCryptoTargets(mSelectedConversation); + boolean hasUnaccepted = !mSelectedConversation.getAcceptedCryptoTargets().containsAll(targets); boolean hasUndecidedOwn = !axolotlService.getKeysWithTrust(XmppAxolotlSession.Trust.UNDECIDED).isEmpty(); boolean hasUndecidedContacts = !axolotlService.getKeysWithTrust(XmppAxolotlSession.Trust.UNDECIDED, targets).isEmpty(); boolean hasPendingKeys = !axolotlService.findDevicesWithoutSession(mSelectedConversation).isEmpty(); boolean hasNoTrustedKeys = axolotlService.anyTargetHasNoTrustedKeys(targets); - if(hasUndecidedOwn || hasUndecidedContacts || hasPendingKeys || hasNoTrustedKeys) { + if(hasUndecidedOwn || hasUndecidedContacts || hasPendingKeys || hasNoTrustedKeys || hasUnaccepted) { axolotlService.createSessionsIfNeeded(mSelectedConversation); Intent intent = new Intent(getApplicationContext(), TrustKeysActivity.class); String[] contacts = new String[targets.size()]; @@ -1545,6 +1546,7 @@ public class ConversationActivity extends XmppActivity intent.putExtra("contacts", contacts); intent.putExtra(EXTRA_ACCOUNT, mSelectedConversation.getAccount().getJid().toBareJid().toString()); intent.putExtra("choice", attachmentChoice); + intent.putExtra("conversation",mSelectedConversation.getUuid()); startActivityForResult(intent, requestCode); 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 8919ac79c..9bccca78b 100644 --- a/src/main/java/eu/siacs/conversations/ui/TrustKeysActivity.java +++ b/src/main/java/eu/siacs/conversations/ui/TrustKeysActivity.java @@ -10,6 +10,8 @@ import android.widget.LinearLayout; import android.widget.TextView; import android.widget.Toast; +import android.util.Log; + import org.whispersystems.libaxolotl.IdentityKey; import java.util.ArrayList; @@ -18,19 +20,21 @@ import java.util.List; import java.util.Map; import java.util.Set; +import eu.siacs.conversations.Config; import eu.siacs.conversations.R; import eu.siacs.conversations.crypto.axolotl.AxolotlService; import eu.siacs.conversations.crypto.axolotl.XmppAxolotlSession; import eu.siacs.conversations.entities.Account; +import eu.siacs.conversations.entities.Conversation; import eu.siacs.conversations.xmpp.OnKeyStatusUpdated; import eu.siacs.conversations.xmpp.jid.InvalidJidException; import eu.siacs.conversations.xmpp.jid.Jid; public class TrustKeysActivity extends XmppActivity implements OnKeyStatusUpdated { - private Jid accountJid; private List contactJids; private Account mAccount; + private Conversation mConversation; private TextView keyErrorMessage; private LinearLayout keyErrorMessageCard; private TextView ownKeysTitle; @@ -71,10 +75,6 @@ public class TrustKeysActivity extends XmppActivity implements OnKeyStatusUpdate protected void onCreate(final Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_trust_keys); - try { - this.accountJid = Jid.fromString(getIntent().getExtras().getString(EXTRA_ACCOUNT)); - } catch (final InvalidJidException ignored) { - } this.contactJids = new ArrayList<>(); for(String jid : getIntent().getStringArrayExtra("contacts")) { try { @@ -126,13 +126,15 @@ public class TrustKeysActivity extends XmppActivity implements OnKeyStatusUpdate synchronized (this.foreignKeysToTrust) { for (Map.Entry> entry : foreignKeysToTrust.entrySet()) { + hasForeignKeys = true; final LinearLayout layout = (LinearLayout) getLayoutInflater().inflate(R.layout.keys_card, foreignKeys, false); + final Jid jid = entry.getKey(); final TextView header = (TextView) layout.findViewById(R.id.foreign_keys_title); final LinearLayout keysContainer = (LinearLayout) layout.findViewById(R.id.foreign_keys_details); - header.setText(entry.getKey().toString()); + final TextView informNoKeys = (TextView) layout.findViewById(R.id.no_keys_to_accept); + header.setText(jid.toString()); final Map fingerprints = entry.getValue(); for (final String fingerprint : fingerprints.keySet()) { - hasForeignKeys = true; addFingerprintRowWithListeners(keysContainer, mAccount, fingerprint, false, XmppAxolotlSession.Trust.fromBoolean(fingerprints.get(fingerprint)), false, new CompoundButton.OnCheckedChangeListener() { @@ -146,11 +148,17 @@ public class TrustKeysActivity extends XmppActivity implements OnKeyStatusUpdate null ); } + if (fingerprints.size() == 0) { + informNoKeys.setVisibility(View.VISIBLE); + informNoKeys.setText(getString(R.string.no_keys_just_confirm,mAccount.getRoster().getContact(jid).getDisplayName())); + } else { + informNoKeys.setVisibility(View.GONE); + } foreignKeys.addView(layout); } } - ownKeysTitle.setText(accountJid.toString()); + ownKeysTitle.setText(mAccount.getJid().toBareJid().toString()); ownKeysCard.setVisibility(hasOwnKeys ? View.VISIBLE : View.GONE); foreignKeys.setVisibility(hasForeignKeys ? View.VISIBLE : View.GONE); if(hasPendingKeyFetches()) { @@ -176,6 +184,7 @@ public class TrustKeysActivity extends XmppActivity implements OnKeyStatusUpdate } private boolean reloadFingerprints() { + List acceptedTargets = mConversation == null ? new ArrayList() : mConversation.getAcceptedCryptoTargets(); ownKeysToTrust.clear(); AxolotlService service = this.mAccount.getAxolotlService(); Set ownKeysSet = service.getKeysWithTrust(XmppAxolotlSession.Trust.UNDECIDED); @@ -197,7 +206,7 @@ public class TrustKeysActivity extends XmppActivity implements OnKeyStatusUpdate foreignFingerprints.put(identityKey.getFingerprint().replaceAll("\\s", ""), false); } } - if (foreignFingerprints.size() > 0) { + if (foreignFingerprints.size() > 0 || !acceptedTargets.contains(jid)) { foreignKeysToTrust.put(jid, foreignFingerprints); } } @@ -207,11 +216,11 @@ public class TrustKeysActivity extends XmppActivity implements OnKeyStatusUpdate @Override public void onBackendConnected() { - if (accountJid != null) { - this.mAccount = xmppConnectionService.findAccountByJid(accountJid); - if (this.mAccount == null) { - return; - } + Intent intent = getIntent(); + this.mAccount = extractAccount(intent); + if (this.mAccount != null && intent != null) { + String uuid = intent.getStringExtra("conversation"); + this.mConversation = xmppConnectionService.findConversationByUuid(uuid); reloadFingerprints(); populateView(); } @@ -276,8 +285,14 @@ public class TrustKeysActivity extends XmppActivity implements OnKeyStatusUpdate fingerprint, XmppAxolotlSession.Trust.fromBoolean(ownKeysToTrust.get(fingerprint))); } + List acceptedTargets = mConversation == null ? new ArrayList() : mConversation.getAcceptedCryptoTargets(); synchronized (this.foreignKeysToTrust) { - for (Map value : foreignKeysToTrust.values()) { + for (Map.Entry> entry : foreignKeysToTrust.entrySet()) { + Jid jid = entry.getKey(); + Map value = entry.getValue(); + if (!acceptedTargets.contains(jid)) { + acceptedTargets.add(jid); + } for (final String fingerprint : value.keySet()) { mAccount.getAxolotlService().setFingerprintTrust( fingerprint, @@ -285,6 +300,11 @@ public class TrustKeysActivity extends XmppActivity implements OnKeyStatusUpdate } } } + if (mConversation != null && mConversation.getMode() == Conversation.MODE_MULTI) { + Log.d(Config.LOGTAG,"commiting accepted crypto targets: "+acceptedTargets); + mConversation.setAcceptedCryptoTargets(acceptedTargets); + //xmppConnectionService.updateConversation(mConversation); + } } private void unlock() { diff --git a/src/main/res/layout/keys_card.xml b/src/main/res/layout/keys_card.xml index 7a5028162..d3271d1bc 100644 --- a/src/main/res/layout/keys_card.xml +++ b/src/main/res/layout/keys_card.xml @@ -1,31 +1,39 @@ - + - + - - + + + \ No newline at end of file diff --git a/src/main/res/values/strings.xml b/src/main/res/values/strings.xml index a25c1a849..69609f880 100644 --- a/src/main/res/values/strings.xml +++ b/src/main/res/values/strings.xml @@ -599,4 +599,5 @@ This field is required Correct message Send corrected message + You already trust this contact. By selecting \'done\' you are just confirming that %s is part of this conference.