diff options
author | Daniel Gultsch <daniel@gultsch.de> | 2016-03-01 11:26:59 +0100 |
---|---|---|
committer | Daniel Gultsch <daniel@gultsch.de> | 2016-03-01 11:26:59 +0100 |
commit | 198dc2c6b444671ec71deb10fbbaaced6e03dced (patch) | |
tree | 407efdea59b9d4eaf8852141272fc153f50f0846 | |
parent | 134c75ae01eee45882d17a4d2fc721f4ccf3ca80 (diff) |
let users confirm each member in a conference even if that contact is already trusted
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 8658dfe2..cc5c2491 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<XmppAxolotlSession> findSessionsForConversation(Conversation conversation) { HashSet<XmppAxolotlSession> 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 f05b3f91..0252ea74 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<Jid> getAcceptedCryptoTargets() { + if (mode == MODE_SINGLE) { + return Arrays.asList(getJid().toBareJid()); + } else { + return getJidListAttribute(ATTRIBUTE_CRYPTO_TARGETS); + } + } + + public void setAcceptedCryptoTargets(List<Jid> acceptedTargets) { + setAttribute(ATTRIBUTE_CRYPTO_TARGETS, acceptedTargets); + } + public void setCorrectingMessage(Message correctingMessage) { this.correctingMessage = correctingMessage; } @@ -794,20 +809,59 @@ 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<Jid> 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<Jid> getJidListAttribute(String key) { + ArrayList<Jid> 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) { diff --git a/src/main/java/eu/siacs/conversations/ui/ConversationActivity.java b/src/main/java/eu/siacs/conversations/ui/ConversationActivity.java index e4ffb3e4..eac53124 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<Jid> 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 8919ac79..9bccca78 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<Jid> 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<Jid, Map<String, Boolean>> 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<String, Boolean> 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<Jid> acceptedTargets = mConversation == null ? new ArrayList<Jid>() : mConversation.getAcceptedCryptoTargets(); ownKeysToTrust.clear(); AxolotlService service = this.mAccount.getAxolotlService(); Set<IdentityKey> 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<Jid> acceptedTargets = mConversation == null ? new ArrayList<Jid>() : mConversation.getAcceptedCryptoTargets(); synchronized (this.foreignKeysToTrust) { - for (Map<String, Boolean> value : foreignKeysToTrust.values()) { + for (Map.Entry<Jid, Map<String, Boolean>> entry : foreignKeysToTrust.entrySet()) { + Jid jid = entry.getKey(); + Map<String, Boolean> 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 7a502816..d3271d1b 100644 --- a/src/main/res/layout/keys_card.xml +++ b/src/main/res/layout/keys_card.xml @@ -1,31 +1,39 @@ <?xml version="1.0" encoding="utf-8"?> -<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" -android:id="@+id/foreign_keys_card" -android:layout_width="fill_parent" -android:layout_height="wrap_content" -android:layout_marginLeft="@dimen/activity_horizontal_margin" -android:layout_marginRight="@dimen/activity_horizontal_margin" -android:layout_marginTop="@dimen/activity_vertical_margin" -android:layout_marginBottom="@dimen/activity_vertical_margin" -android:background="@drawable/infocard_border" -android:orientation="vertical" -android:padding="@dimen/infocard_padding"> +<LinearLayout android:id="@+id/foreign_keys_card" + xmlns:android="http://schemas.android.com/apk/res/android" + android:layout_width="fill_parent" + android:layout_height="wrap_content" + android:layout_marginBottom="@dimen/activity_vertical_margin" + android:layout_marginLeft="@dimen/activity_horizontal_margin" + android:layout_marginRight="@dimen/activity_horizontal_margin" + android:layout_marginTop="@dimen/activity_vertical_margin" + android:background="@drawable/infocard_border" + android:orientation="vertical" + android:padding="@dimen/infocard_padding"> -<TextView - android:id="@+id/foreign_keys_title" - android:layout_width="wrap_content" - android:layout_height="wrap_content" - android:textColor="@color/black87" - android:textSize="?attr/TextSizeHeadline" - android:textStyle="bold"/> + <TextView + android:id="@+id/foreign_keys_title" + android:layout_width="wrap_content" + android:layout_height="wrap_content" + android:textColor="@color/black87" + android:textSize="?attr/TextSizeHeadline" + android:textStyle="bold"/> -<LinearLayout - android:id="@+id/foreign_keys_details" - android:layout_width="fill_parent" - android:layout_height="wrap_content" - android:divider="?android:dividerHorizontal" - android:showDividers="middle" - android:orientation="vertical"> -</LinearLayout> + <LinearLayout + android:id="@+id/foreign_keys_details" + android:layout_width="fill_parent" + android:layout_height="wrap_content" + android:divider="?android:dividerHorizontal" + android:orientation="vertical" + android:showDividers="middle"> + </LinearLayout> + <TextView + android:layout_marginTop="8dp" + android:id="@+id/no_keys_to_accept" + android:layout_width="wrap_content" + android:layout_height="wrap_content" + android:textColor="@color/black87" + android:text="@string/no_keys_just_confirm" + android:textSize="?attr/TextSizeBody"/> </LinearLayout>
\ No newline at end of file diff --git a/src/main/res/values/strings.xml b/src/main/res/values/strings.xml index a25c1a84..69609f88 100644 --- a/src/main/res/values/strings.xml +++ b/src/main/res/values/strings.xml @@ -599,4 +599,5 @@ <string name="this_field_is_required">This field is required</string> <string name="correct_message">Correct message</string> <string name="send_corrected_message">Send corrected message</string> + <string name="no_keys_just_confirm">You already trust this contact. By selecting \'done\' you are just confirming that %s is part of this conference.</string> </resources> |