From 87746ca2ba62bc5e2893e4e6626e92ce87d6b15a Mon Sep 17 00:00:00 2001 From: Daniel Gultsch Date: Fri, 16 Dec 2016 17:12:26 +0100 Subject: remove own fetch errors from device announcement --- .../java/eu/siacs/conversations/OmemoActivity.java | 290 -------------------- .../crypto/axolotl/AxolotlService.java | 74 ++++-- .../conversations/ui/ContactDetailsActivity.java | 3 - .../conversations/ui/EditAccountActivity.java | 1 - .../eu/siacs/conversations/ui/OmemoActivity.java | 292 +++++++++++++++++++++ .../siacs/conversations/ui/TrustKeysActivity.java | 2 - 6 files changed, 337 insertions(+), 325 deletions(-) delete mode 100644 src/main/java/eu/siacs/conversations/OmemoActivity.java create mode 100644 src/main/java/eu/siacs/conversations/ui/OmemoActivity.java diff --git a/src/main/java/eu/siacs/conversations/OmemoActivity.java b/src/main/java/eu/siacs/conversations/OmemoActivity.java deleted file mode 100644 index c0c7b298..00000000 --- a/src/main/java/eu/siacs/conversations/OmemoActivity.java +++ /dev/null @@ -1,290 +0,0 @@ -package eu.siacs.conversations; - -import android.app.AlertDialog; -import android.content.DialogInterface; -import android.content.Intent; -import android.os.Bundle; -import android.view.ContextMenu; -import android.view.MenuItem; -import android.view.View; -import android.widget.CompoundButton; -import android.widget.ImageView; -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 java.security.cert.X509Certificate; -import java.util.Arrays; - -import eu.siacs.conversations.crypto.axolotl.FingerprintStatus; -import eu.siacs.conversations.crypto.axolotl.XmppAxolotlSession; -import eu.siacs.conversations.entities.Account; -import eu.siacs.conversations.ui.TrustKeysActivity; -import eu.siacs.conversations.ui.XmppActivity; -import eu.siacs.conversations.ui.widget.Switch; -import eu.siacs.conversations.utils.CryptoHelper; -import eu.siacs.conversations.utils.XmppUri; - - -public abstract class OmemoActivity extends XmppActivity { - - private Account mSelectedAccount; - private String mSelectedFingerprint; - - protected XmppUri mPendingFingerprintVerificationUri = null; - - @Override - public void onCreateContextMenu(ContextMenu menu, View v, ContextMenu.ContextMenuInfo menuInfo) { - super.onCreateContextMenu(menu,v,menuInfo); - Object account = v.getTag(R.id.TAG_ACCOUNT); - Object fingerprint = v.getTag(R.id.TAG_FINGERPRINT); - Object fingerprintStatus = v.getTag(R.id.TAG_FINGERPRINT_STATUS);; - if (account != null - && fingerprint != null - && account instanceof Account - && fingerprintStatus != null - && fingerprint instanceof String - && fingerprintStatus instanceof FingerprintStatus) { - getMenuInflater().inflate(R.menu.omemo_key_context, menu); - MenuItem purgeItem = menu.findItem(R.id.purge_omemo_key); - MenuItem verifyScan = menu.findItem(R.id.verify_scan); - if (this instanceof TrustKeysActivity) { - purgeItem.setVisible(false); - verifyScan.setVisible(false); - } else { - FingerprintStatus status = (FingerprintStatus) fingerprintStatus; - if (!status.isActive() || status.isVerified()) { - verifyScan.setVisible(false); - } - } - this.mSelectedAccount = (Account) account; - this.mSelectedFingerprint = (String) fingerprint; - } - } - - @Override - public boolean onContextItemSelected(MenuItem item) { - switch (item.getItemId()) { - case R.id.purge_omemo_key: - showPurgeKeyDialog(mSelectedAccount,mSelectedFingerprint); - break; - case R.id.copy_omemo_key: - copyOmemoFingerprint(mSelectedFingerprint); - break; - case R.id.verify_scan: - new IntentIntegrator(this).initiateScan(Arrays.asList("AZTEC","QR_CODE")); - break; - } - return true; - } - - @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); - } else { - this.mPendingFingerprintVerificationUri =uri; - } - } - } - - protected abstract void processFingerprintVerification(XmppUri uri); - - protected void copyOmemoFingerprint(String fingerprint) { - if (copyTextToClipboard(CryptoHelper.prettifyFingerprint(fingerprint.substring(2)), R.string.omemo_fingerprint)) { - Toast.makeText( - this, - R.string.toast_message_omemo_fingerprint, - Toast.LENGTH_SHORT).show(); - } - } - - protected void addFingerprintRow(LinearLayout keys, final XmppAxolotlSession session, boolean highlight) { - final Account account = session.getAccount(); - final String fingerprint = session.getFingerprint(); - addFingerprintRowWithListeners(keys, - session.getAccount(), - session.getFingerprint(), - highlight, - session.getTrust(), - true, - true, - new CompoundButton.OnCheckedChangeListener() { - @Override - public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) { - account.getAxolotlService().setFingerprintTrust(fingerprint, FingerprintStatus.createActive(isChecked)); - } - }); - } - - protected void addFingerprintRowWithListeners(LinearLayout keys, final Account account, - final String fingerprint, - boolean highlight, - FingerprintStatus status, - boolean showTag, - boolean undecidedNeedEnablement, - CompoundButton.OnCheckedChangeListener - onCheckedChangeListener) { - View view = getLayoutInflater().inflate(R.layout.contact_key, keys, false); - TextView key = (TextView) view.findViewById(R.id.key); - TextView keyType = (TextView) view.findViewById(R.id.key_type); - if (Config.X509_VERIFICATION && status.getTrust() == FingerprintStatus.Trust.VERIFIED_X509) { - View.OnClickListener listener = new View.OnClickListener() { - @Override - public void onClick(View v) { - showX509Certificate(account,fingerprint); - } - }; - key.setOnClickListener(listener); - keyType.setOnClickListener(listener); - } - Switch trustToggle = (Switch) view.findViewById(R.id.tgl_trust); - ImageView verifiedFingerprintSymbol = (ImageView) view.findViewById(R.id.verified_fingerprint); - trustToggle.setVisibility(View.VISIBLE); - registerForContextMenu(view); - view.setTag(R.id.TAG_ACCOUNT,account); - view.setTag(R.id.TAG_FINGERPRINT,fingerprint); - view.setTag(R.id.TAG_FINGERPRINT_STATUS,status); - boolean x509 = Config.X509_VERIFICATION && status.getTrust() == FingerprintStatus.Trust.VERIFIED_X509; - final View.OnClickListener toast; - trustToggle.setChecked(status.isTrusted(), false); - - if (status.isActive()){ - key.setTextColor(getPrimaryTextColor()); - keyType.setTextColor(getSecondaryTextColor()); - if (status.isVerified()) { - verifiedFingerprintSymbol.setVisibility(View.VISIBLE); - verifiedFingerprintSymbol.setAlpha(1.0f); - trustToggle.setVisibility(View.GONE); - verifiedFingerprintSymbol.setOnClickListener(new View.OnClickListener() { - @Override - public void onClick(View v) { - replaceToast(getString(R.string.this_device_has_been_verified), false); - } - }); - toast = null; - } else { - verifiedFingerprintSymbol.setVisibility(View.GONE); - trustToggle.setVisibility(View.VISIBLE); - trustToggle.setOnCheckedChangeListener(onCheckedChangeListener); - if (status.getTrust() == FingerprintStatus.Trust.UNDECIDED && undecidedNeedEnablement) { - trustToggle.setOnClickListener(new View.OnClickListener() { - @Override - public void onClick(View v) { - account.getAxolotlService().setFingerprintTrust(fingerprint,FingerprintStatus.createActive(false)); - v.setEnabled(true); - v.setOnClickListener(null); - } - }); - trustToggle.setEnabled(false); - } else { - trustToggle.setOnClickListener(null); - trustToggle.setEnabled(true); - } - toast = new View.OnClickListener() { - @Override - public void onClick(View v) { - hideToast(); - } - }; - } - } else { - key.setTextColor(getTertiaryTextColor()); - keyType.setTextColor(getTertiaryTextColor()); - toast = new View.OnClickListener() { - @Override - public void onClick(View v) { - replaceToast(getString(R.string.this_device_is_no_longer_in_use), false); - } - }; - if (status.isVerified()) { - trustToggle.setVisibility(View.GONE); - verifiedFingerprintSymbol.setVisibility(View.VISIBLE); - verifiedFingerprintSymbol.setAlpha(0.4368f); - verifiedFingerprintSymbol.setOnClickListener(toast); - } else { - trustToggle.setVisibility(View.VISIBLE); - verifiedFingerprintSymbol.setVisibility(View.GONE); - trustToggle.setOnClickListener(null); - trustToggle.setEnabled(false); - trustToggle.setOnClickListener(toast); - } - } - - view.setOnClickListener(toast); - key.setOnClickListener(toast); - keyType.setOnClickListener(toast); - if (showTag) { - keyType.setText(getString(x509 ? R.string.omemo_fingerprint_x509 : R.string.omemo_fingerprint)); - } else { - keyType.setVisibility(View.GONE); - } - if (highlight) { - keyType.setTextColor(getResources().getColor(R.color.accent)); - keyType.setText(getString(x509 ? R.string.omemo_fingerprint_x509_selected_message : R.string.omemo_fingerprint_selected_message)); - } else { - keyType.setText(getString(x509 ? R.string.omemo_fingerprint_x509 : R.string.omemo_fingerprint)); - } - - key.setText(CryptoHelper.prettifyFingerprint(fingerprint.substring(2))); - - keys.addView(view); - } - - public void showPurgeKeyDialog(final Account account, final String fingerprint) { - AlertDialog.Builder builder = new AlertDialog.Builder(this); - builder.setTitle(getString(R.string.purge_key)); - builder.setIconAttribute(android.R.attr.alertDialogIcon); - builder.setMessage(getString(R.string.purge_key_desc_part1) - + "\n\n" + CryptoHelper.prettifyFingerprint(fingerprint.substring(2)) - + "\n\n" + getString(R.string.purge_key_desc_part2)); - builder.setNegativeButton(getString(R.string.cancel), null); - builder.setPositiveButton(getString(R.string.purge_key), - new DialogInterface.OnClickListener() { - @Override - public void onClick(DialogInterface dialog, int which) { - account.getAxolotlService().purgeKey(fingerprint); - refreshUi(); - } - }); - builder.create().show(); - } - - private void showX509Certificate(Account account, String fingerprint) { - X509Certificate x509Certificate = account.getAxolotlService().getFingerprintCertificate(fingerprint); - if (x509Certificate != null) { - showCertificateInformationDialog(CryptoHelper.extractCertificateInformation(x509Certificate)); - } else { - Toast.makeText(this,R.string.certificate_not_found, Toast.LENGTH_SHORT).show(); - } - } - - private void showCertificateInformationDialog(Bundle bundle) { - View view = getLayoutInflater().inflate(R.layout.certificate_information, null); - final String not_available = getString(R.string.certicate_info_not_available); - TextView subject_cn = (TextView) view.findViewById(R.id.subject_cn); - TextView subject_o = (TextView) view.findViewById(R.id.subject_o); - TextView issuer_cn = (TextView) view.findViewById(R.id.issuer_cn); - TextView issuer_o = (TextView) view.findViewById(R.id.issuer_o); - TextView sha1 = (TextView) view.findViewById(R.id.sha1); - - subject_cn.setText(bundle.getString("subject_cn", not_available)); - subject_o.setText(bundle.getString("subject_o", not_available)); - issuer_cn.setText(bundle.getString("issuer_cn", not_available)); - issuer_o.setText(bundle.getString("issuer_o", not_available)); - sha1.setText(bundle.getString("sha1", not_available)); - - AlertDialog.Builder builder = new AlertDialog.Builder(this); - builder.setTitle(R.string.certificate_information); - builder.setView(view); - builder.setPositiveButton(R.string.ok, null); - builder.create().show(); - } -} 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 09beb22c..6bd10c15 100644 --- a/src/main/java/eu/siacs/conversations/crypto/axolotl/AxolotlService.java +++ b/src/main/java/eu/siacs/conversations/crypto/axolotl/AxolotlService.java @@ -395,7 +395,7 @@ public class AxolotlService implements OnAdvancedStreamFeaturesLoaded { XmppAxolotlSession session = sessions.get(address); if (session != null && session.getFingerprint() != null) { if (!session.getTrust().isActive()) { - Log.d(Config.LOGTAG,"reactivating device with fingprint "+session.getFingerprint()); + Log.d(Config.LOGTAG,"reactivating device with fingerprint "+session.getFingerprint()); session.setTrust(session.getTrust().toActive()); } } @@ -407,7 +407,11 @@ public class AxolotlService implements OnAdvancedStreamFeaturesLoaded { for (Integer deviceId : deviceIds) { AxolotlAddress ownDeviceAddress = new AxolotlAddress(jid.toBareJid().toPreppedString(), deviceId); if (sessions.get(ownDeviceAddress) == null) { - buildSessionFromPEP(ownDeviceAddress); + FetchStatus status = fetchStatusMap.get(ownDeviceAddress); + if (status == null || status == FetchStatus.TIMEOUT) { + fetchStatusMap.put(ownDeviceAddress, FetchStatus.PENDING); + this.buildSessionFromPEP(ownDeviceAddress); + } } } if (needsPublishing) { @@ -462,10 +466,13 @@ public class AxolotlService implements OnAdvancedStreamFeaturesLoaded { long diff = System.currentTimeMillis() - session.getTrust().getLastActivation(); if (diff > Config.OMEMO_AUTO_EXPIRY) { long lastMessageDiff = System.currentTimeMillis() - mXmppConnectionService.databaseBackend.getLastTimeFingerprintUsed(account,session.getFingerprint()); + long hours = Math.round(lastMessageDiff/(1000*60.0*60.0)); if (lastMessageDiff > Config.OMEMO_AUTO_EXPIRY) { devices.add(session.getRemoteAddress().getDeviceId()); session.setTrust(session.getTrust().toInactive()); - Log.d(Config.LOGTAG, "added own device " + session.getFingerprint() + " to list of expired devices. Last message received "+(lastMessageDiff/1000)+"s ago"); + Log.d(Config.LOGTAG,account.getJid().toBareJid()+": added own device " + session.getFingerprint() + " to list of expired devices. Last message received "+hours+" hours ago"); + } else { + Log.d(Config.LOGTAG,account.getJid().toBareJid()+": own device "+session.getFingerprint()+" was active "+hours+" hours ago"); } } } @@ -475,34 +482,32 @@ public class AxolotlService implements OnAdvancedStreamFeaturesLoaded { public void publishOwnDeviceId(Set deviceIds) { Set deviceIdsCopy = new HashSet<>(deviceIds); - if (!deviceIdsCopy.contains(getOwnDeviceId())) { - Log.d(Config.LOGTAG, AxolotlService.getLogprefix(account) + "Own device " + getOwnDeviceId() + " not in PEP devicelist."); - if (deviceIdsCopy.isEmpty()) { - if (numPublishTriesOnEmptyPep >= publishTriesThreshold) { - Log.w(Config.LOGTAG, getLogprefix(account) + "Own device publish attempt threshold exceeded, aborting..."); - pepBroken = true; - return; - } else { - numPublishTriesOnEmptyPep++; - Log.w(Config.LOGTAG, getLogprefix(account) + "Own device list empty, attempting to publish (try " + numPublishTriesOnEmptyPep + ")"); - } + Log.d(Config.LOGTAG, AxolotlService.getLogprefix(account) + "publishing own device ids"); + if (deviceIdsCopy.isEmpty()) { + if (numPublishTriesOnEmptyPep >= publishTriesThreshold) { + Log.w(Config.LOGTAG, getLogprefix(account) + "Own device publish attempt threshold exceeded, aborting..."); + pepBroken = true; + return; } else { - numPublishTriesOnEmptyPep = 0; + numPublishTriesOnEmptyPep++; + Log.w(Config.LOGTAG, getLogprefix(account) + "Own device list empty, attempting to publish (try " + numPublishTriesOnEmptyPep + ")"); } - deviceIdsCopy.add(getOwnDeviceId()); - IqPacket publish = mXmppConnectionService.getIqGenerator().publishDeviceIds(deviceIdsCopy); - ownPushPending.set(true); - mXmppConnectionService.sendIqPacket(account, publish, new OnIqPacketReceived() { - @Override - public void onIqPacketReceived(Account account, IqPacket packet) { - ownPushPending.set(false); - if (packet.getType() == IqPacket.TYPE.ERROR) { - pepBroken = true; - Log.d(Config.LOGTAG, getLogprefix(account) + "Error received while publishing own device id" + packet.findChild("error")); - } - } - }); + } else { + numPublishTriesOnEmptyPep = 0; } + deviceIdsCopy.add(getOwnDeviceId()); + IqPacket publish = mXmppConnectionService.getIqGenerator().publishDeviceIds(deviceIdsCopy); + ownPushPending.set(true); + mXmppConnectionService.sendIqPacket(account, publish, new OnIqPacketReceived() { + @Override + public void onIqPacketReceived(Account account, IqPacket packet) { + ownPushPending.set(false); + if (packet.getType() == IqPacket.TYPE.ERROR) { + pepBroken = true; + Log.d(Config.LOGTAG, getLogprefix(account) + "Error received while publishing own device id" + packet.findChild("error")); + } + } + }); } public void publishDeviceVerificationAndBundle(final SignedPreKeyRecord signedPreKeyRecord, @@ -797,10 +802,21 @@ public class AxolotlService implements OnAdvancedStreamFeaturesLoaded { } mXmppConnectionService.keyStatusUpdated(report); } + Set ownDeviceIds = new HashSet<>(getOwnDeviceIds()); + boolean publish = false; + for(Map.Entry entry : own.entrySet()) { + if (entry.getValue() == FetchStatus.ERROR && ownDeviceIds.remove(entry.getKey())) { + publish = true; + Log.d(Config.LOGTAG,account.getJid().toBareJid()+": error fetching own device with id "+entry.getKey()+". removing from annoucement"); + } + } + if (publish) { + publishOwnDeviceId(ownDeviceIds); + } } private void buildSessionFromPEP(final AxolotlAddress address) { - Log.i(Config.LOGTAG, AxolotlService.getLogprefix(account) + "Building new sesstion for " + address.toString()); + Log.i(Config.LOGTAG, AxolotlService.getLogprefix(account) + "Building new session for " + address.toString()); if (address.getDeviceId() == getOwnDeviceId()) { throw new AssertionError("We should NEVER build a session with ourselves. What happened here?!"); } diff --git a/src/main/java/eu/siacs/conversations/ui/ContactDetailsActivity.java b/src/main/java/eu/siacs/conversations/ui/ContactDetailsActivity.java index 296a10c2..ea3816f7 100644 --- a/src/main/java/eu/siacs/conversations/ui/ContactDetailsActivity.java +++ b/src/main/java/eu/siacs/conversations/ui/ContactDetailsActivity.java @@ -32,15 +32,12 @@ import com.wefika.flowlayout.FlowLayout; import org.openintents.openpgp.util.OpenPgpUtils; -import java.security.cert.X509Certificate; import java.util.List; import eu.siacs.conversations.Config; -import eu.siacs.conversations.OmemoActivity; import eu.siacs.conversations.R; import eu.siacs.conversations.crypto.PgpEngine; 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.Contact; diff --git a/src/main/java/eu/siacs/conversations/ui/EditAccountActivity.java b/src/main/java/eu/siacs/conversations/ui/EditAccountActivity.java index e1035db6..3f6bd434 100644 --- a/src/main/java/eu/siacs/conversations/ui/EditAccountActivity.java +++ b/src/main/java/eu/siacs/conversations/ui/EditAccountActivity.java @@ -41,7 +41,6 @@ import java.util.Set; import java.util.concurrent.atomic.AtomicInteger; import eu.siacs.conversations.Config; -import eu.siacs.conversations.OmemoActivity; import eu.siacs.conversations.R; import eu.siacs.conversations.crypto.axolotl.AxolotlService; import eu.siacs.conversations.crypto.axolotl.XmppAxolotlSession; diff --git a/src/main/java/eu/siacs/conversations/ui/OmemoActivity.java b/src/main/java/eu/siacs/conversations/ui/OmemoActivity.java new file mode 100644 index 00000000..8ce8c14d --- /dev/null +++ b/src/main/java/eu/siacs/conversations/ui/OmemoActivity.java @@ -0,0 +1,292 @@ +package eu.siacs.conversations.ui; + +import android.app.AlertDialog; +import android.content.DialogInterface; +import android.content.Intent; +import android.os.Bundle; +import android.view.ContextMenu; +import android.view.MenuItem; +import android.view.View; +import android.widget.CompoundButton; +import android.widget.ImageView; +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 java.security.cert.X509Certificate; +import java.util.Arrays; + +import eu.siacs.conversations.Config; +import eu.siacs.conversations.R; +import eu.siacs.conversations.crypto.axolotl.FingerprintStatus; +import eu.siacs.conversations.crypto.axolotl.XmppAxolotlSession; +import eu.siacs.conversations.entities.Account; +import eu.siacs.conversations.ui.TrustKeysActivity; +import eu.siacs.conversations.ui.XmppActivity; +import eu.siacs.conversations.ui.widget.Switch; +import eu.siacs.conversations.utils.CryptoHelper; +import eu.siacs.conversations.utils.XmppUri; + + +public abstract class OmemoActivity extends XmppActivity { + + private Account mSelectedAccount; + private String mSelectedFingerprint; + + protected XmppUri mPendingFingerprintVerificationUri = null; + + @Override + public void onCreateContextMenu(ContextMenu menu, View v, ContextMenu.ContextMenuInfo menuInfo) { + super.onCreateContextMenu(menu,v,menuInfo); + Object account = v.getTag(R.id.TAG_ACCOUNT); + Object fingerprint = v.getTag(R.id.TAG_FINGERPRINT); + Object fingerprintStatus = v.getTag(R.id.TAG_FINGERPRINT_STATUS);; + if (account != null + && fingerprint != null + && account instanceof Account + && fingerprintStatus != null + && fingerprint instanceof String + && fingerprintStatus instanceof FingerprintStatus) { + getMenuInflater().inflate(R.menu.omemo_key_context, menu); + MenuItem purgeItem = menu.findItem(R.id.purge_omemo_key); + MenuItem verifyScan = menu.findItem(R.id.verify_scan); + if (this instanceof TrustKeysActivity) { + purgeItem.setVisible(false); + verifyScan.setVisible(false); + } else { + FingerprintStatus status = (FingerprintStatus) fingerprintStatus; + if (!status.isActive() || status.isVerified()) { + verifyScan.setVisible(false); + } + } + this.mSelectedAccount = (Account) account; + this.mSelectedFingerprint = (String) fingerprint; + } + } + + @Override + public boolean onContextItemSelected(MenuItem item) { + switch (item.getItemId()) { + case R.id.purge_omemo_key: + showPurgeKeyDialog(mSelectedAccount,mSelectedFingerprint); + break; + case R.id.copy_omemo_key: + copyOmemoFingerprint(mSelectedFingerprint); + break; + case R.id.verify_scan: + new IntentIntegrator(this).initiateScan(Arrays.asList("AZTEC","QR_CODE")); + break; + } + return true; + } + + @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); + } else { + this.mPendingFingerprintVerificationUri =uri; + } + } + } + + protected abstract void processFingerprintVerification(XmppUri uri); + + protected void copyOmemoFingerprint(String fingerprint) { + if (copyTextToClipboard(CryptoHelper.prettifyFingerprint(fingerprint.substring(2)), R.string.omemo_fingerprint)) { + Toast.makeText( + this, + R.string.toast_message_omemo_fingerprint, + Toast.LENGTH_SHORT).show(); + } + } + + protected void addFingerprintRow(LinearLayout keys, final XmppAxolotlSession session, boolean highlight) { + final Account account = session.getAccount(); + final String fingerprint = session.getFingerprint(); + addFingerprintRowWithListeners(keys, + session.getAccount(), + session.getFingerprint(), + highlight, + session.getTrust(), + true, + true, + new CompoundButton.OnCheckedChangeListener() { + @Override + public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) { + account.getAxolotlService().setFingerprintTrust(fingerprint, FingerprintStatus.createActive(isChecked)); + } + }); + } + + protected void addFingerprintRowWithListeners(LinearLayout keys, final Account account, + final String fingerprint, + boolean highlight, + FingerprintStatus status, + boolean showTag, + boolean undecidedNeedEnablement, + CompoundButton.OnCheckedChangeListener + onCheckedChangeListener) { + View view = getLayoutInflater().inflate(R.layout.contact_key, keys, false); + TextView key = (TextView) view.findViewById(R.id.key); + TextView keyType = (TextView) view.findViewById(R.id.key_type); + if (Config.X509_VERIFICATION && status.getTrust() == FingerprintStatus.Trust.VERIFIED_X509) { + View.OnClickListener listener = new View.OnClickListener() { + @Override + public void onClick(View v) { + showX509Certificate(account,fingerprint); + } + }; + key.setOnClickListener(listener); + keyType.setOnClickListener(listener); + } + Switch trustToggle = (Switch) view.findViewById(R.id.tgl_trust); + ImageView verifiedFingerprintSymbol = (ImageView) view.findViewById(R.id.verified_fingerprint); + trustToggle.setVisibility(View.VISIBLE); + registerForContextMenu(view); + view.setTag(R.id.TAG_ACCOUNT,account); + view.setTag(R.id.TAG_FINGERPRINT,fingerprint); + view.setTag(R.id.TAG_FINGERPRINT_STATUS,status); + boolean x509 = Config.X509_VERIFICATION && status.getTrust() == FingerprintStatus.Trust.VERIFIED_X509; + final View.OnClickListener toast; + trustToggle.setChecked(status.isTrusted(), false); + + if (status.isActive()){ + key.setTextColor(getPrimaryTextColor()); + keyType.setTextColor(getSecondaryTextColor()); + if (status.isVerified()) { + verifiedFingerprintSymbol.setVisibility(View.VISIBLE); + verifiedFingerprintSymbol.setAlpha(1.0f); + trustToggle.setVisibility(View.GONE); + verifiedFingerprintSymbol.setOnClickListener(new View.OnClickListener() { + @Override + public void onClick(View v) { + replaceToast(getString(R.string.this_device_has_been_verified), false); + } + }); + toast = null; + } else { + verifiedFingerprintSymbol.setVisibility(View.GONE); + trustToggle.setVisibility(View.VISIBLE); + trustToggle.setOnCheckedChangeListener(onCheckedChangeListener); + if (status.getTrust() == FingerprintStatus.Trust.UNDECIDED && undecidedNeedEnablement) { + trustToggle.setOnClickListener(new View.OnClickListener() { + @Override + public void onClick(View v) { + account.getAxolotlService().setFingerprintTrust(fingerprint,FingerprintStatus.createActive(false)); + v.setEnabled(true); + v.setOnClickListener(null); + } + }); + trustToggle.setEnabled(false); + } else { + trustToggle.setOnClickListener(null); + trustToggle.setEnabled(true); + } + toast = new View.OnClickListener() { + @Override + public void onClick(View v) { + hideToast(); + } + }; + } + } else { + key.setTextColor(getTertiaryTextColor()); + keyType.setTextColor(getTertiaryTextColor()); + toast = new View.OnClickListener() { + @Override + public void onClick(View v) { + replaceToast(getString(R.string.this_device_is_no_longer_in_use), false); + } + }; + if (status.isVerified()) { + trustToggle.setVisibility(View.GONE); + verifiedFingerprintSymbol.setVisibility(View.VISIBLE); + verifiedFingerprintSymbol.setAlpha(0.4368f); + verifiedFingerprintSymbol.setOnClickListener(toast); + } else { + trustToggle.setVisibility(View.VISIBLE); + verifiedFingerprintSymbol.setVisibility(View.GONE); + trustToggle.setOnClickListener(null); + trustToggle.setEnabled(false); + trustToggle.setOnClickListener(toast); + } + } + + view.setOnClickListener(toast); + key.setOnClickListener(toast); + keyType.setOnClickListener(toast); + if (showTag) { + keyType.setText(getString(x509 ? R.string.omemo_fingerprint_x509 : R.string.omemo_fingerprint)); + } else { + keyType.setVisibility(View.GONE); + } + if (highlight) { + keyType.setTextColor(getResources().getColor(R.color.accent)); + keyType.setText(getString(x509 ? R.string.omemo_fingerprint_x509_selected_message : R.string.omemo_fingerprint_selected_message)); + } else { + keyType.setText(getString(x509 ? R.string.omemo_fingerprint_x509 : R.string.omemo_fingerprint)); + } + + key.setText(CryptoHelper.prettifyFingerprint(fingerprint.substring(2))); + + keys.addView(view); + } + + public void showPurgeKeyDialog(final Account account, final String fingerprint) { + AlertDialog.Builder builder = new AlertDialog.Builder(this); + builder.setTitle(getString(R.string.purge_key)); + builder.setIconAttribute(android.R.attr.alertDialogIcon); + builder.setMessage(getString(R.string.purge_key_desc_part1) + + "\n\n" + CryptoHelper.prettifyFingerprint(fingerprint.substring(2)) + + "\n\n" + getString(R.string.purge_key_desc_part2)); + builder.setNegativeButton(getString(R.string.cancel), null); + builder.setPositiveButton(getString(R.string.purge_key), + new DialogInterface.OnClickListener() { + @Override + public void onClick(DialogInterface dialog, int which) { + account.getAxolotlService().purgeKey(fingerprint); + refreshUi(); + } + }); + builder.create().show(); + } + + private void showX509Certificate(Account account, String fingerprint) { + X509Certificate x509Certificate = account.getAxolotlService().getFingerprintCertificate(fingerprint); + if (x509Certificate != null) { + showCertificateInformationDialog(CryptoHelper.extractCertificateInformation(x509Certificate)); + } else { + Toast.makeText(this,R.string.certificate_not_found, Toast.LENGTH_SHORT).show(); + } + } + + private void showCertificateInformationDialog(Bundle bundle) { + View view = getLayoutInflater().inflate(R.layout.certificate_information, null); + final String not_available = getString(R.string.certicate_info_not_available); + TextView subject_cn = (TextView) view.findViewById(R.id.subject_cn); + TextView subject_o = (TextView) view.findViewById(R.id.subject_o); + TextView issuer_cn = (TextView) view.findViewById(R.id.issuer_cn); + TextView issuer_o = (TextView) view.findViewById(R.id.issuer_o); + TextView sha1 = (TextView) view.findViewById(R.id.sha1); + + subject_cn.setText(bundle.getString("subject_cn", not_available)); + subject_o.setText(bundle.getString("subject_o", not_available)); + issuer_cn.setText(bundle.getString("issuer_cn", not_available)); + issuer_o.setText(bundle.getString("issuer_o", not_available)); + sha1.setText(bundle.getString("sha1", not_available)); + + AlertDialog.Builder builder = new AlertDialog.Builder(this); + builder.setTitle(R.string.certificate_information); + builder.setView(view); + builder.setPositiveButton(R.string.ok, null); + builder.create().show(); + } +} diff --git a/src/main/java/eu/siacs/conversations/ui/TrustKeysActivity.java b/src/main/java/eu/siacs/conversations/ui/TrustKeysActivity.java index 1f7951e4..02556d31 100644 --- a/src/main/java/eu/siacs/conversations/ui/TrustKeysActivity.java +++ b/src/main/java/eu/siacs/conversations/ui/TrustKeysActivity.java @@ -16,7 +16,6 @@ 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; @@ -28,7 +27,6 @@ import java.util.Map; import java.util.Set; import eu.siacs.conversations.Config; -import eu.siacs.conversations.OmemoActivity; import eu.siacs.conversations.R; import eu.siacs.conversations.crypto.axolotl.AxolotlService; import eu.siacs.conversations.crypto.axolotl.FingerprintStatus; -- cgit v1.2.3