OmemoActivity.java

  1package eu.siacs.conversations.ui;
  2
  3import android.databinding.DataBindingUtil;
  4import android.support.v7.app.AlertDialog;
  5import android.content.Intent;
  6import android.os.Bundle;
  7import android.support.v4.content.ContextCompat;
  8import android.view.ContextMenu;
  9import android.view.MenuItem;
 10import android.view.View;
 11import android.widget.CompoundButton;
 12
 13import android.widget.LinearLayout;
 14import android.widget.TextView;
 15import android.widget.Toast;
 16
 17import java.security.cert.X509Certificate;
 18import java.util.Arrays;
 19
 20import eu.siacs.conversations.Config;
 21import eu.siacs.conversations.R;
 22import eu.siacs.conversations.crypto.axolotl.FingerprintStatus;
 23import eu.siacs.conversations.crypto.axolotl.XmppAxolotlSession;
 24import eu.siacs.conversations.databinding.ContactKeyBinding;
 25import eu.siacs.conversations.entities.Account;
 26import eu.siacs.conversations.utils.CryptoHelper;
 27import eu.siacs.conversations.utils.XmppUri;
 28
 29public abstract class OmemoActivity extends XmppActivity {
 30
 31    private Account mSelectedAccount;
 32    private String mSelectedFingerprint;
 33
 34    protected XmppUri mPendingFingerprintVerificationUri = null;
 35
 36    @Override
 37    public void onCreateContextMenu(ContextMenu menu, View v, ContextMenu.ContextMenuInfo menuInfo) {
 38        super.onCreateContextMenu(menu,v,menuInfo);
 39        Object account = v.getTag(R.id.TAG_ACCOUNT);
 40        Object fingerprint = v.getTag(R.id.TAG_FINGERPRINT);
 41        Object fingerprintStatus = v.getTag(R.id.TAG_FINGERPRINT_STATUS);
 42        if (account != null
 43                && fingerprint != null
 44                && account instanceof Account
 45                && fingerprintStatus != null
 46                && fingerprint instanceof String
 47                && fingerprintStatus instanceof FingerprintStatus) {
 48            getMenuInflater().inflate(R.menu.omemo_key_context, menu);
 49            MenuItem distrust = menu.findItem(R.id.distrust_key);
 50            MenuItem verifyScan = menu.findItem(R.id.verify_scan);
 51            if (this instanceof TrustKeysActivity) {
 52                distrust.setVisible(false);
 53                verifyScan.setVisible(false);
 54            } else {
 55                FingerprintStatus status = (FingerprintStatus) fingerprintStatus;
 56                if (!status.isActive() || status.isVerified()) {
 57                    verifyScan.setVisible(false);
 58                }
 59                distrust.setVisible(status.isVerified() || (!status.isActive() && status.isTrusted()));
 60            }
 61            this.mSelectedAccount = (Account) account;
 62            this.mSelectedFingerprint = (String) fingerprint;
 63        }
 64    }
 65
 66    @Override
 67    public boolean onContextItemSelected(MenuItem item) {
 68        switch (item.getItemId()) {
 69            case R.id.distrust_key:
 70                showPurgeKeyDialog(mSelectedAccount,mSelectedFingerprint);
 71                break;
 72            case R.id.copy_omemo_key:
 73                copyOmemoFingerprint(mSelectedFingerprint);
 74                break;
 75            case R.id.verify_scan:
 76                //new IntentIntegrator(this).initiateScan(Arrays.asList("AZTEC","QR_CODE"));
 77                break;
 78        }
 79        return true;
 80    }
 81
 82    @Override
 83    public void onActivityResult(int requestCode, int resultCode, Intent intent) {
 84        /*IntentResult scanResult = IntentIntegrator.parseActivityResult(requestCode, resultCode, intent);
 85        if (scanResult != null && scanResult.getFormatName() != null) {
 86            String data = scanResult.getContents();
 87            XmppUri uri = new XmppUri(data);
 88            if (xmppConnectionServiceBound) {
 89                processFingerprintVerification(uri);
 90            } else {
 91                this.mPendingFingerprintVerificationUri =uri;
 92            }
 93        }*/
 94    }
 95
 96    protected abstract void processFingerprintVerification(XmppUri uri);
 97
 98    protected void copyOmemoFingerprint(String fingerprint) {
 99        if (copyTextToClipboard(CryptoHelper.prettifyFingerprint(fingerprint.substring(2)), R.string.omemo_fingerprint)) {
100            Toast.makeText(
101                    this,
102                    R.string.toast_message_omemo_fingerprint,
103                    Toast.LENGTH_SHORT).show();
104        }
105    }
106
107    protected void addFingerprintRow(LinearLayout keys, final XmppAxolotlSession session, boolean highlight) {
108        final Account account = session.getAccount();
109        final String fingerprint = session.getFingerprint();
110        addFingerprintRowWithListeners(keys,
111                session.getAccount(),
112                fingerprint,
113                highlight,
114                session.getTrust(),
115                true,
116                true,
117                (buttonView, isChecked) -> account.getAxolotlService().setFingerprintTrust(fingerprint, FingerprintStatus.createActive(isChecked)));
118    }
119
120    protected void addFingerprintRowWithListeners(LinearLayout keys, final Account account,
121                                                     final String fingerprint,
122                                                     boolean highlight,
123                                                     FingerprintStatus status,
124                                                     boolean showTag,
125                                                     boolean undecidedNeedEnablement,
126                                                     CompoundButton.OnCheckedChangeListener
127                                                             onCheckedChangeListener) {
128        ContactKeyBinding binding = DataBindingUtil.inflate(getLayoutInflater(),R.layout.contact_key,keys,true);
129        if (Config.X509_VERIFICATION && status.getTrust() == FingerprintStatus.Trust.VERIFIED_X509) {
130            binding.key.setOnClickListener(v -> showX509Certificate(account,fingerprint));
131            binding.keyType.setOnClickListener(v -> showX509Certificate(account,fingerprint));
132        }
133        binding.tglTrust.setVisibility(View.VISIBLE);
134        registerForContextMenu(binding.getRoot());
135        binding.getRoot().setTag(R.id.TAG_ACCOUNT,account);
136        binding.getRoot().setTag(R.id.TAG_FINGERPRINT,fingerprint);
137        binding.getRoot().setTag(R.id.TAG_FINGERPRINT_STATUS,status);
138        boolean x509 = Config.X509_VERIFICATION && status.getTrust() == FingerprintStatus.Trust.VERIFIED_X509;
139        final View.OnClickListener toast;
140        binding.tglTrust.setChecked(status.isTrusted());
141
142        if (status.isActive()){
143            binding.key.setTextColor(getPrimaryTextColor());
144            binding.keyType.setTextColor(getSecondaryTextColor());
145            if (status.isVerified()) {
146                binding.verifiedFingerprint.setVisibility(View.VISIBLE);
147                binding.verifiedFingerprint.setAlpha(1.0f);
148                binding.tglTrust.setVisibility(View.GONE);
149                binding.verifiedFingerprint.setOnClickListener(v -> replaceToast(getString(R.string.this_device_has_been_verified), false));
150                toast = null;
151            } else {
152                binding.verifiedFingerprint.setVisibility(View.GONE);
153                binding.tglTrust.setVisibility(View.VISIBLE);
154                binding.tglTrust.setOnCheckedChangeListener(onCheckedChangeListener);
155                if (status.getTrust() == FingerprintStatus.Trust.UNDECIDED && undecidedNeedEnablement) {
156                    binding.buttonEnableDevice.setVisibility(View.VISIBLE);
157                    binding.buttonEnableDevice.setOnClickListener(v -> {
158                        account.getAxolotlService().setFingerprintTrust(fingerprint,FingerprintStatus.createActive(false));
159                        binding.buttonEnableDevice.setVisibility(View.GONE);
160                        binding.tglTrust.setVisibility(View.VISIBLE);
161                    });
162                    binding.tglTrust.setVisibility(View.GONE);
163                } else {
164                    binding.tglTrust.setOnClickListener(null);
165                    binding.tglTrust.setEnabled(true);
166                }
167                toast = v -> hideToast();
168            }
169        } else {
170            binding.key.setTextColor(getTertiaryTextColor());
171            binding.keyType.setTextColor(getTertiaryTextColor());
172            toast = v -> replaceToast(getString(R.string.this_device_is_no_longer_in_use), false);
173            if (status.isVerified()) {
174                binding.tglTrust.setVisibility(View.GONE);
175                binding.verifiedFingerprint.setVisibility(View.VISIBLE);
176                binding.verifiedFingerprint.setAlpha(0.4368f);
177                binding.verifiedFingerprint.setOnClickListener(toast);
178            } else {
179                binding.tglTrust.setVisibility(View.VISIBLE);
180                binding.verifiedFingerprint.setVisibility(View.GONE);
181                binding.tglTrust.setEnabled(false);
182            }
183        }
184
185        binding.getRoot().setOnClickListener(toast);
186        binding.key.setOnClickListener(toast);
187        binding.keyType.setOnClickListener(toast);
188        if (showTag) {
189            binding.keyType.setText(getString(x509 ? R.string.omemo_fingerprint_x509 : R.string.omemo_fingerprint));
190        } else {
191            binding.keyType.setVisibility(View.GONE);
192        }
193        if (highlight) {
194            binding.keyType.setTextColor(ContextCompat.getColor(this, R.color.accent));
195            binding.keyType.setText(getString(x509 ? R.string.omemo_fingerprint_x509_selected_message : R.string.omemo_fingerprint_selected_message));
196        } else {
197            binding.keyType.setText(getString(x509 ? R.string.omemo_fingerprint_x509 : R.string.omemo_fingerprint));
198        }
199
200        binding.key.setText(CryptoHelper.prettifyFingerprint(fingerprint.substring(2)));
201    }
202
203    public void showPurgeKeyDialog(final Account account, final String fingerprint) {
204        AlertDialog.Builder builder = new AlertDialog.Builder(this);
205        builder.setTitle(R.string.distrust_omemo_key);
206        builder.setMessage(R.string.distrust_omemo_key_text);
207        builder.setNegativeButton(getString(R.string.cancel), null);
208        builder.setPositiveButton(R.string.confirm,
209                (dialog, which) -> {
210                    account.getAxolotlService().distrustFingerprint(fingerprint);
211                    refreshUi();
212                });
213        builder.create().show();
214    }
215
216    private void showX509Certificate(Account account, String fingerprint) {
217        X509Certificate x509Certificate = account.getAxolotlService().getFingerprintCertificate(fingerprint);
218        if (x509Certificate != null) {
219            showCertificateInformationDialog(CryptoHelper.extractCertificateInformation(x509Certificate));
220        } else {
221            Toast.makeText(this,R.string.certificate_not_found, Toast.LENGTH_SHORT).show();
222        }
223    }
224
225    private void showCertificateInformationDialog(Bundle bundle) {
226        View view = getLayoutInflater().inflate(R.layout.certificate_information, null);
227        final String not_available = getString(R.string.certicate_info_not_available);
228        TextView subject_cn = (TextView) view.findViewById(R.id.subject_cn);
229        TextView subject_o = (TextView) view.findViewById(R.id.subject_o);
230        TextView issuer_cn = (TextView) view.findViewById(R.id.issuer_cn);
231        TextView issuer_o = (TextView) view.findViewById(R.id.issuer_o);
232        TextView sha1 = (TextView) view.findViewById(R.id.sha1);
233
234        subject_cn.setText(bundle.getString("subject_cn", not_available));
235        subject_o.setText(bundle.getString("subject_o", not_available));
236        issuer_cn.setText(bundle.getString("issuer_cn", not_available));
237        issuer_o.setText(bundle.getString("issuer_o", not_available));
238        sha1.setText(bundle.getString("sha1", not_available));
239
240        AlertDialog.Builder builder = new AlertDialog.Builder(this);
241        builder.setTitle(R.string.certificate_information);
242        builder.setView(view);
243        builder.setPositiveButton(R.string.ok, null);
244        builder.create().show();
245    }
246}