VerifyOTRActivity.java

  1package eu.siacs.conversations.ui;
  2
  3import android.content.Intent;
  4import android.os.Bundle;
  5import android.view.View;
  6import android.widget.Button;
  7import android.widget.EditText;
  8import android.widget.RelativeLayout;
  9import android.widget.TextView;
 10import android.widget.Toast;
 11
 12import net.java.otr4j.OtrException;
 13import net.java.otr4j.session.Session;
 14
 15import eu.siacs.conversations.R;
 16import eu.siacs.conversations.entities.Account;
 17import eu.siacs.conversations.entities.Conversation;
 18import eu.siacs.conversations.services.XmppConnectionService;
 19import eu.siacs.conversations.utils.CryptoHelper;
 20import eu.siacs.conversations.xmpp.jid.InvalidJidException;
 21import eu.siacs.conversations.xmpp.jid.Jid;
 22
 23public class VerifyOTRActivity extends XmppActivity implements XmppConnectionService.OnConversationUpdate {
 24
 25	public static final String ACTION_VERIFY_CONTACT = "verify_contact";
 26
 27	private RelativeLayout mVerificationAreaOne;
 28	private RelativeLayout mVerificationAreaTwo;
 29	private TextView mErrorNoSession;
 30	private TextView mRemoteJid;
 31	private TextView mRemoteFingerprint;
 32	private TextView mYourFingerprint;
 33	private EditText mSharedSecretHint;
 34	private EditText mSharedSecretSecret;
 35	private Button mButtonVerifyFingerprint;
 36	private Button mButtonSharedSecretPositive;
 37	private Button mButtonSharedSecretNegative;
 38	private TextView mStatusMessage;
 39	private Account mAccount;
 40	private Conversation mConversation;
 41
 42	private View.OnClickListener mVerifyFingerprintListener = new View.OnClickListener() {
 43
 44		@Override
 45		public void onClick(View view) {
 46			mConversation.verifyOtrFingerprint();
 47			finish();
 48		}
 49	};
 50
 51	private View.OnClickListener mCreateSharedSecretListener = new View.OnClickListener() {
 52		@Override
 53		public void onClick(final View view) {
 54			if (isAccountOnline()) {
 55				final String question = mSharedSecretHint.getText().toString();
 56				final String secret = mSharedSecretSecret.getText().toString();
 57				initSmp(question, secret);
 58				updateView();
 59			}
 60		}
 61	};
 62	private View.OnClickListener mCancelSharedSecretListener = new View.OnClickListener() {
 63		@Override
 64		public void onClick(View view) {
 65			if (isAccountOnline()) {
 66				abortSmp();
 67				updateView();
 68			}
 69		}
 70	};
 71	private View.OnClickListener mRespondSharedSecretListener = new View.OnClickListener() {
 72
 73		@Override
 74		public void onClick(View view) {
 75			if (isAccountOnline()) {
 76				final String question = mSharedSecretHint.getText().toString();
 77				final String secret = mSharedSecretSecret.getText().toString();
 78				respondSmp(question, secret);
 79				updateView();
 80			}
 81		}
 82	};
 83	private View.OnClickListener mRetrySharedSecretListener = new View.OnClickListener() {
 84		@Override
 85		public void onClick(View view) {
 86			mConversation.smp().status = Conversation.Smp.STATUS_NONE;
 87			mConversation.smp().hint = null;
 88			mConversation.smp().secret = null;
 89			updateView();
 90		}
 91	};
 92	private View.OnClickListener mFinishListener = new View.OnClickListener() {
 93		@Override
 94		public void onClick(View view) {
 95			mConversation.smp().status = Conversation.Smp.STATUS_NONE;
 96			finish();
 97		}
 98	};
 99
100	protected boolean initSmp(final String question, final String secret) {
101		final Session session = mConversation.getOtrSession();
102		if (session!=null) {
103			try {
104				session.initSmp(question, secret);
105				mConversation.smp().status = Conversation.Smp.STATUS_WE_REQUESTED;
106				return true;
107			} catch (OtrException e) {
108				return false;
109			}
110		} else {
111			return false;
112		}
113	}
114
115	protected boolean abortSmp() {
116		final Session session = mConversation.getOtrSession();
117		if (session!=null) {
118			try {
119				session.abortSmp();
120				mConversation.smp().status = Conversation.Smp.STATUS_NONE;
121				mConversation.smp().hint = null;
122				mConversation.smp().secret = null;
123				return true;
124			} catch (OtrException e) {
125				return false;
126			}
127		} else {
128			return false;
129		}
130	}
131
132	protected boolean respondSmp(final String question, final String secret) {
133		final Session session = mConversation.getOtrSession();
134		if (session!=null) {
135			try {
136				session.respondSmp(question,secret);
137				return true;
138			} catch (OtrException e) {
139				return false;
140			}
141		} else {
142			return false;
143		}
144	}
145
146	protected boolean isAccountOnline() {
147		if (this.mAccount.getStatus() != Account.State.ONLINE) {
148			Toast.makeText(this,R.string.not_connected_try_again,Toast.LENGTH_SHORT).show();
149			return false;
150		} else {
151			return true;
152		}
153	}
154
155	protected boolean handleIntent(Intent intent) {
156		if (intent.getAction().equals(ACTION_VERIFY_CONTACT)) {
157			try {
158				this.mAccount = this.xmppConnectionService.findAccountByJid(Jid.fromString(intent.getExtras().getString("account")));
159			} catch (final InvalidJidException ignored) {
160				return false;
161			}
162			try {
163				this.mConversation = this.xmppConnectionService.find(this.mAccount,Jid.fromString(intent.getExtras().getString("contact")));
164				if (this.mConversation == null) {
165					return false;
166				}
167			} catch (final InvalidJidException ignored) {
168				return false;
169			}
170			return true;
171		} else {
172			return false;
173		}
174	}
175
176	@Override
177	protected void onBackendConnected() {
178		if (handleIntent(getIntent())) {
179			updateView();
180		}
181	}
182
183	protected void updateView() {
184		if (this.mConversation.hasValidOtrSession()) {
185			this.mVerificationAreaOne.setVisibility(View.VISIBLE);
186			this.mVerificationAreaTwo.setVisibility(View.VISIBLE);
187			this.mErrorNoSession.setVisibility(View.GONE);
188			this.mYourFingerprint.setText(CryptoHelper.prettifyFingerprint(this.mAccount.getOtrFingerprint()));
189			this.mRemoteFingerprint.setText(this.mConversation.getOtrFingerprint());
190			this.mRemoteJid.setText(this.mConversation.getContact().getJid().toBareJid().toString());
191			Conversation.Smp smp = mConversation.smp();
192			Session session = mConversation.getOtrSession();
193			if (mConversation.isOtrFingerprintVerified()) {
194				deactivateButton(mButtonVerifyFingerprint, R.string.verified);
195			} else {
196				activateButton(mButtonVerifyFingerprint, R.string.verify, mVerifyFingerprintListener);
197			}
198			if (smp.status == Conversation.Smp.STATUS_NONE) {
199				activateButton(mButtonSharedSecretPositive, R.string.create, mCreateSharedSecretListener);
200				deactivateButton(mButtonSharedSecretNegative, R.string.cancel);
201				this.mSharedSecretHint.setFocusableInTouchMode(true);
202				this.mSharedSecretSecret.setFocusableInTouchMode(true);
203				this.mSharedSecretSecret.setText("");
204				this.mSharedSecretHint.setText("");
205				this.mSharedSecretHint.setVisibility(View.VISIBLE);
206				this.mSharedSecretSecret.setVisibility(View.VISIBLE);
207				this.mStatusMessage.setVisibility(View.GONE);
208			} else if (smp.status == Conversation.Smp.STATUS_CONTACT_REQUESTED) {
209				this.mSharedSecretHint.setFocusable(false);
210				this.mSharedSecretHint.setText(smp.hint);
211				this.mSharedSecretSecret.setFocusableInTouchMode(true);
212				this.mSharedSecretHint.setVisibility(View.VISIBLE);
213				this.mSharedSecretSecret.setVisibility(View.VISIBLE);
214				this.mStatusMessage.setVisibility(View.GONE);
215				deactivateButton(mButtonSharedSecretNegative, R.string.cancel);
216				activateButton(mButtonSharedSecretPositive, R.string.respond, mRespondSharedSecretListener);
217			} else if (smp.status == Conversation.Smp.STATUS_FAILED) {
218				activateButton(mButtonSharedSecretNegative, R.string.cancel, mFinishListener);
219				activateButton(mButtonSharedSecretPositive, R.string.try_again, mRetrySharedSecretListener);
220				this.mSharedSecretHint.setVisibility(View.GONE);
221				this.mSharedSecretSecret.setVisibility(View.GONE);
222				this.mStatusMessage.setVisibility(View.VISIBLE);
223				this.mStatusMessage.setText(R.string.secrets_do_not_match);
224				this.mStatusMessage.setTextColor(getWarningTextColor());
225			} else if (smp.status == Conversation.Smp.STATUS_VERIFIED) {
226				this.mSharedSecretHint.setVisibility(View.GONE);
227				this.mSharedSecretSecret.setVisibility(View.GONE);
228				this.mStatusMessage.setVisibility(View.VISIBLE);
229				this.mStatusMessage.setText(R.string.verified);
230				this.mStatusMessage.setTextColor(getPrimaryColor());
231				deactivateButton(mButtonSharedSecretNegative, R.string.cancel);
232				activateButton(mButtonSharedSecretPositive, R.string.finish, mFinishListener);
233			} else if (session != null && session.isSmpInProgress()) {
234				deactivateButton(mButtonSharedSecretPositive, R.string.in_progress);
235				activateButton(mButtonSharedSecretNegative, R.string.cancel, mCancelSharedSecretListener);
236				this.mSharedSecretHint.setVisibility(View.VISIBLE);
237				this.mSharedSecretSecret.setVisibility(View.VISIBLE);
238				this.mSharedSecretHint.setFocusable(false);
239				this.mSharedSecretSecret.setFocusable(false);
240			}
241		} else {
242			this.mVerificationAreaOne.setVisibility(View.GONE);
243			this.mVerificationAreaTwo.setVisibility(View.GONE);
244			this.mErrorNoSession.setVisibility(View.VISIBLE);
245		}
246	}
247
248	protected void activateButton(Button button, int text, View.OnClickListener listener) {
249		button.setEnabled(true);
250		button.setTextColor(getPrimaryTextColor());
251		button.setText(text);
252		button.setOnClickListener(listener);
253	}
254
255	protected void deactivateButton(Button button, int text) {
256		button.setEnabled(false);
257		button.setTextColor(getSecondaryTextColor());
258		button.setText(text);
259		button.setOnClickListener(null);
260	}
261
262	@Override
263	protected void onCreate(Bundle savedInstanceState) {
264		super.onCreate(savedInstanceState);
265		setContentView(R.layout.activity_verify_otr);
266		this.mRemoteFingerprint = (TextView) findViewById(R.id.remote_fingerprint);
267		this.mRemoteJid = (TextView) findViewById(R.id.remote_jid);
268		this.mYourFingerprint = (TextView) findViewById(R.id.your_fingerprint);
269		this.mButtonSharedSecretNegative = (Button) findViewById(R.id.button_shared_secret_negative);
270		this.mButtonSharedSecretPositive = (Button) findViewById(R.id.button_shared_secret_positive);
271		this.mButtonVerifyFingerprint = (Button) findViewById(R.id.button_verify_fingerprint);
272		this.mSharedSecretSecret = (EditText) findViewById(R.id.shared_secret_secret);
273		this.mSharedSecretHint = (EditText) findViewById(R.id.shared_secret_hint);
274		this.mStatusMessage= (TextView) findViewById(R.id.status_message);
275		this.mVerificationAreaOne = (RelativeLayout) findViewById(R.id.verification_area_one);
276		this.mVerificationAreaTwo = (RelativeLayout) findViewById(R.id.verification_area_two);
277		this.mErrorNoSession = (TextView) findViewById(R.id.error_no_session);
278	}
279
280	@Override
281	protected String getShareableUri() {
282		if (mAccount!=null) {
283			return mAccount.getShareableUri();
284		} else {
285			return "";
286		}
287	}
288
289	public void onConversationUpdate() {
290		runOnUiThread(new Runnable() {
291			@Override
292			public void run() {
293				updateView();
294			}
295		});
296	}
297}