VerifyOTRActivity.java

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