OmemoActivity.java

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