Merge branch 'feature/otr_verification' into development
This commit is contained in:
commit
5b9c690c47
|
@ -95,6 +95,10 @@
|
|||
android:name=".ui.PublishProfilePictureActivity"
|
||||
android:label="@string/mgmt_account_publish_avatar"
|
||||
android:windowSoftInputMode="stateHidden" />
|
||||
<activity
|
||||
android:name=".ui.VerifyOTRActivity"
|
||||
android:label="@string/verify_otr"
|
||||
android:windowSoftInputMode="stateHidden" />
|
||||
<activity
|
||||
android:name=".ui.ShareWithActivity"
|
||||
android:label="@string/title_activity_conversations" >
|
||||
|
|
|
@ -18,13 +18,18 @@ import android.util.Log;
|
|||
|
||||
import eu.siacs.conversations.Config;
|
||||
import eu.siacs.conversations.entities.Account;
|
||||
import eu.siacs.conversations.entities.Conversation;
|
||||
import eu.siacs.conversations.services.XmppConnectionService;
|
||||
import eu.siacs.conversations.xmpp.jid.InvalidJidException;
|
||||
import eu.siacs.conversations.xmpp.jid.Jid;
|
||||
import eu.siacs.conversations.xmpp.stanzas.MessagePacket;
|
||||
|
||||
import net.java.otr4j.OtrEngineHost;
|
||||
import net.java.otr4j.OtrException;
|
||||
import net.java.otr4j.OtrPolicy;
|
||||
import net.java.otr4j.OtrPolicyImpl;
|
||||
import net.java.otr4j.crypto.OtrCryptoEngineImpl;
|
||||
import net.java.otr4j.crypto.OtrCryptoException;
|
||||
import net.java.otr4j.session.InstanceTag;
|
||||
import net.java.otr4j.session.SessionID;
|
||||
|
||||
|
@ -92,9 +97,18 @@ public class OtrEngine implements OtrEngineHost {
|
|||
}
|
||||
|
||||
@Override
|
||||
public void askForSecret(SessionID arg0, InstanceTag arg1, String arg2) {
|
||||
// TODO Auto-generated method stub
|
||||
|
||||
public void askForSecret(SessionID id, InstanceTag instanceTag, String question) {
|
||||
try {
|
||||
final Jid jid = Jid.fromSessionID(id);
|
||||
Conversation conversation = this.mXmppConnectionService.find(this.account,jid);
|
||||
if (conversation!=null) {
|
||||
conversation.smp().hint = question;
|
||||
conversation.smp().status = Conversation.Smp.STATUS_CONTACT_REQUESTED;
|
||||
mXmppConnectionService.updateConversationUi();
|
||||
}
|
||||
} catch (InvalidJidException e) {
|
||||
Log.d(Config.LOGTAG,account.getJid().toBareJid()+": smp in invalid session "+id.toString());
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -110,8 +124,11 @@ public class OtrEngine implements OtrEngineHost {
|
|||
|
||||
@Override
|
||||
public byte[] getLocalFingerprintRaw(SessionID arg0) {
|
||||
// TODO Auto-generated method stub
|
||||
return null;
|
||||
try {
|
||||
return new OtrCryptoEngineImpl().getFingerprintRaw(getPublicKey());
|
||||
} catch (OtrCryptoException e) {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
public PublicKey getPublicKey() {
|
||||
|
@ -187,20 +204,31 @@ public class OtrEngine implements OtrEngineHost {
|
|||
|
||||
@Override
|
||||
public void showError(SessionID arg0, String arg1) throws OtrException {
|
||||
// TODO Auto-generated method stub
|
||||
|
||||
Log.d(Config.LOGTAG,"show error");
|
||||
}
|
||||
|
||||
@Override
|
||||
public void smpAborted(SessionID arg0) throws OtrException {
|
||||
// TODO Auto-generated method stub
|
||||
public void smpAborted(SessionID id) throws OtrException {
|
||||
setSmpStatus(id, Conversation.Smp.STATUS_NONE);
|
||||
}
|
||||
|
||||
private void setSmpStatus(SessionID id, int status) {
|
||||
try {
|
||||
final Jid jid = Jid.fromSessionID(id);
|
||||
Conversation conversation = this.mXmppConnectionService.find(this.account,jid);
|
||||
if (conversation!=null) {
|
||||
conversation.smp().status = status;
|
||||
mXmppConnectionService.updateConversationUi();
|
||||
}
|
||||
} catch (final InvalidJidException ignored) {
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void smpError(SessionID arg0, int arg1, boolean arg2)
|
||||
public void smpError(SessionID id, int arg1, boolean arg2)
|
||||
throws OtrException {
|
||||
throw new OtrException(new Exception("smp error"));
|
||||
setSmpStatus(id, Conversation.Smp.STATUS_NONE);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -211,19 +239,29 @@ public class OtrEngine implements OtrEngineHost {
|
|||
|
||||
@Override
|
||||
public void unreadableMessageReceived(SessionID arg0) throws OtrException {
|
||||
Log.d(Config.LOGTAG,"unreadable message received");
|
||||
throw new OtrException(new Exception("unreadable message received"));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void unverify(SessionID arg0, String arg1) {
|
||||
// TODO Auto-generated method stub
|
||||
|
||||
public void unverify(SessionID id, String arg1) {
|
||||
setSmpStatus(id, Conversation.Smp.STATUS_FAILED);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void verify(SessionID arg0, String arg1, boolean arg2) {
|
||||
// TODO Auto-generated method stub
|
||||
|
||||
public void verify(SessionID id, String arg1, boolean arg2) {
|
||||
try {
|
||||
final Jid jid = Jid.fromSessionID(id);
|
||||
Conversation conversation = this.mXmppConnectionService.find(this.account,jid);
|
||||
if (conversation!=null) {
|
||||
conversation.smp().hint = null;
|
||||
conversation.smp().status = Conversation.Smp.STATUS_VERIFIED;
|
||||
conversation.verifyOtrFingerprint();
|
||||
mXmppConnectionService.updateConversationUi();
|
||||
mXmppConnectionService.syncRosterToDisk(conversation.getAccount());
|
||||
}
|
||||
} catch (final InvalidJidException ignored) {
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -63,13 +63,12 @@ public class Conversation extends AbstractEntity {
|
|||
private transient SessionImpl otrSession;
|
||||
|
||||
private transient String otrFingerprint = null;
|
||||
private Smp mSmp = new Smp();
|
||||
|
||||
private String nextMessage;
|
||||
|
||||
private transient MucOptions mucOptions = null;
|
||||
|
||||
// private transient String latestMarkableMessageId;
|
||||
|
||||
private byte[] symmetricKey;
|
||||
|
||||
private Bookmark bookmark;
|
||||
|
@ -271,6 +270,13 @@ public class Conversation extends AbstractEntity {
|
|||
public void resetOtrSession() {
|
||||
this.otrFingerprint = null;
|
||||
this.otrSession = null;
|
||||
this.mSmp.hint = null;
|
||||
this.mSmp.secret = null;
|
||||
this.mSmp.status = Smp.STATUS_NONE;
|
||||
}
|
||||
|
||||
public Smp smp() {
|
||||
return mSmp;
|
||||
}
|
||||
|
||||
public void startOtrIfNeeded() {
|
||||
|
@ -330,6 +336,14 @@ public class Conversation extends AbstractEntity {
|
|||
return this.otrFingerprint;
|
||||
}
|
||||
|
||||
public void verifyOtrFingerprint() {
|
||||
getContact().addOtrFingerprint(getOtrFingerprint());
|
||||
}
|
||||
|
||||
public boolean isOtrFingerprintVerified() {
|
||||
return getContact().getOtrFingerprints().contains(getOtrFingerprint());
|
||||
}
|
||||
|
||||
public synchronized MucOptions getMucOptions() {
|
||||
if (this.mucOptions == null) {
|
||||
this.mucOptions = new MucOptions(this);
|
||||
|
@ -403,6 +417,10 @@ public class Conversation extends AbstractEntity {
|
|||
}
|
||||
}
|
||||
|
||||
public boolean smpRequested() {
|
||||
return smp().status == Smp.STATUS_CONTACT_REQUESTED;
|
||||
}
|
||||
|
||||
public void setNextMessage(String message) {
|
||||
this.nextMessage = message;
|
||||
}
|
||||
|
@ -503,4 +521,16 @@ public class Conversation extends AbstractEntity {
|
|||
this.messages.addAll(index, messages);
|
||||
}
|
||||
}
|
||||
|
||||
public class Smp {
|
||||
public static final int STATUS_NONE = 0;
|
||||
public static final int STATUS_CONTACT_REQUESTED = 1;
|
||||
public static final int STATUS_WE_REQUESTED = 2;
|
||||
public static final int STATUS_FAILED = 3;
|
||||
public static final int STATUS_VERIFIED = 4;
|
||||
|
||||
public String secret = null;
|
||||
public String hint = null;
|
||||
public int status = 0;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -35,7 +35,6 @@ import net.java.otr4j.session.SessionStatus;
|
|||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
import java.util.concurrent.ConcurrentLinkedQueue;
|
||||
|
||||
import eu.siacs.conversations.R;
|
||||
|
@ -53,7 +52,6 @@ import eu.siacs.conversations.ui.XmppActivity.OnValueEdited;
|
|||
import eu.siacs.conversations.ui.adapter.MessageAdapter;
|
||||
import eu.siacs.conversations.ui.adapter.MessageAdapter.OnContactPictureClicked;
|
||||
import eu.siacs.conversations.ui.adapter.MessageAdapter.OnContactPictureLongClicked;
|
||||
import eu.siacs.conversations.utils.UIHelper;
|
||||
import eu.siacs.conversations.xmpp.jid.Jid;
|
||||
|
||||
public class ConversationFragment extends Fragment {
|
||||
|
@ -146,6 +144,19 @@ public class ConversationFragment extends Fragment {
|
|||
}
|
||||
}
|
||||
};
|
||||
protected OnClickListener clickToVerify = new OnClickListener() {
|
||||
|
||||
@Override
|
||||
public void onClick(View v) {
|
||||
if (conversation.getOtrFingerprint() != null) {
|
||||
Intent intent = new Intent(getActivity(), VerifyOTRActivity.class);
|
||||
intent.setAction(VerifyOTRActivity.ACTION_VERIFY_CONTACT);
|
||||
intent.putExtra("contact", conversation.getContact().getJid().toBareJid().toString());
|
||||
intent.putExtra("account", conversation.getAccount().getJid().toBareJid().toString());
|
||||
startActivity(intent);
|
||||
}
|
||||
}
|
||||
};
|
||||
private ConcurrentLinkedQueue<Message> mEncryptedMessages = new ConcurrentLinkedQueue<>();
|
||||
private boolean mDecryptJobRunning = false;
|
||||
private OnEditorActionListener mEditorActionListener = new OnEditorActionListener() {
|
||||
|
@ -296,7 +307,7 @@ public class ConversationFragment extends Fragment {
|
|||
.getConversation());
|
||||
}
|
||||
}
|
||||
} else {
|
||||
} else {
|
||||
Account account = message.getConversation().getAccount();
|
||||
Intent intent = new Intent(activity, EditAccountActivity.class);
|
||||
intent.putExtra("jid", account.getJid().toBareJid().toString());
|
||||
|
@ -505,6 +516,39 @@ public class ConversationFragment extends Fragment {
|
|||
activity.switchToContactDetails(contact);
|
||||
}
|
||||
});
|
||||
} else if (conversation.getMode() == Conversation.MODE_SINGLE) {
|
||||
makeFingerprintWarning();
|
||||
} else if (!conversation.getMucOptions().online()
|
||||
&& conversation.getAccount().getStatus() == Account.STATUS_ONLINE) {
|
||||
int error = conversation.getMucOptions().getError();
|
||||
switch (error) {
|
||||
case MucOptions.ERROR_NICK_IN_USE:
|
||||
showSnackbar(R.string.nick_in_use, R.string.edit,
|
||||
clickToMuc);
|
||||
break;
|
||||
case MucOptions.ERROR_ROOM_NOT_FOUND:
|
||||
showSnackbar(R.string.conference_not_found,
|
||||
R.string.leave, leaveMuc);
|
||||
break;
|
||||
case MucOptions.ERROR_PASSWORD_REQUIRED:
|
||||
showSnackbar(R.string.conference_requires_password,
|
||||
R.string.enter_password, enterPassword);
|
||||
break;
|
||||
case MucOptions.ERROR_BANNED:
|
||||
showSnackbar(R.string.conference_banned,
|
||||
R.string.leave, leaveMuc);
|
||||
break;
|
||||
case MucOptions.ERROR_MEMBERS_ONLY:
|
||||
showSnackbar(R.string.conference_members_only,
|
||||
R.string.leave, leaveMuc);
|
||||
break;
|
||||
case MucOptions.KICKED_FROM_ROOM:
|
||||
showSnackbar(R.string.conference_kicked, R.string.join,
|
||||
joinMuc);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
for (Message message : this.conversation.getMessages()) {
|
||||
if (message.getEncryption() == Message.ENCRYPTION_PGP
|
||||
|
@ -526,44 +570,6 @@ public class ConversationFragment extends Fragment {
|
|||
updateStatusMessages();
|
||||
}
|
||||
this.messageListAdapter.notifyDataSetChanged();
|
||||
if (conversation.getMode() == Conversation.MODE_SINGLE) {
|
||||
if (messageList.size() >= 1) {
|
||||
makeFingerprintWarning();
|
||||
}
|
||||
} else {
|
||||
if (!conversation.getMucOptions().online()
|
||||
&& conversation.getAccount().getStatus() == Account.STATUS_ONLINE) {
|
||||
int error = conversation.getMucOptions().getError();
|
||||
switch (error) {
|
||||
case MucOptions.ERROR_NICK_IN_USE:
|
||||
showSnackbar(R.string.nick_in_use, R.string.edit,
|
||||
clickToMuc);
|
||||
break;
|
||||
case MucOptions.ERROR_ROOM_NOT_FOUND:
|
||||
showSnackbar(R.string.conference_not_found,
|
||||
R.string.leave, leaveMuc);
|
||||
break;
|
||||
case MucOptions.ERROR_PASSWORD_REQUIRED:
|
||||
showSnackbar(R.string.conference_requires_password,
|
||||
R.string.enter_password, enterPassword);
|
||||
break;
|
||||
case MucOptions.ERROR_BANNED:
|
||||
showSnackbar(R.string.conference_banned,
|
||||
R.string.leave, leaveMuc);
|
||||
break;
|
||||
case MucOptions.ERROR_MEMBERS_ONLY:
|
||||
showSnackbar(R.string.conference_members_only,
|
||||
R.string.leave, leaveMuc);
|
||||
break;
|
||||
case MucOptions.KICKED_FROM_ROOM:
|
||||
showSnackbar(R.string.conference_kicked, R.string.join,
|
||||
joinMuc);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
updateChatMsgHint();
|
||||
if (!activity.isConversationsOverviewVisable() || !activity.isConversationsOverviewHideable()) {
|
||||
activity.xmppConnectionService.markRead(conversation, true);
|
||||
|
@ -680,26 +686,11 @@ public class ConversationFragment extends Fragment {
|
|||
}
|
||||
|
||||
protected void makeFingerprintWarning() {
|
||||
Set<String> knownFingerprints = conversation.getContact()
|
||||
.getOtrFingerprints();
|
||||
if (conversation.hasValidOtrSession()
|
||||
&& (!conversation.isMuted())
|
||||
&& (conversation.getOtrSession().getSessionStatus() == SessionStatus.ENCRYPTED) && (!knownFingerprints
|
||||
.contains(conversation.getOtrFingerprint()))) {
|
||||
showSnackbar(R.string.unknown_otr_fingerprint, R.string.verify,
|
||||
new OnClickListener() {
|
||||
|
||||
@Override
|
||||
public void onClick(View v) {
|
||||
if (conversation.getOtrFingerprint() != null) {
|
||||
AlertDialog dialog = UIHelper
|
||||
.getVerifyFingerprintDialog(
|
||||
(ConversationActivity) getActivity(),
|
||||
conversation, snackbar);
|
||||
dialog.show();
|
||||
}
|
||||
}
|
||||
});
|
||||
if (conversation.smpRequested()) {
|
||||
showSnackbar(R.string.smp_requested, R.string.verify, clickToVerify);
|
||||
} else if (conversation.hasValidOtrSession() && (conversation.getOtrSession().getSessionStatus() == SessionStatus.ENCRYPTED)
|
||||
&& (!conversation.isOtrFingerprintVerified())) {
|
||||
showSnackbar(R.string.unknown_otr_fingerprint, R.string.verify, clickToVerify);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -826,15 +817,15 @@ public class ConversationFragment extends Fragment {
|
|||
final ConversationActivity activity = (ConversationActivity) getActivity();
|
||||
final XmppConnectionService xmppService = activity.xmppConnectionService;
|
||||
activity.selectPresence(message.getConversation(),
|
||||
new OnPresenceSelected() {
|
||||
new OnPresenceSelected() {
|
||||
|
||||
@Override
|
||||
public void onPresenceSelected() {
|
||||
message.setCounterpart(conversation.getNextCounterpart());
|
||||
xmppService.sendMessage(message);
|
||||
messageSent();
|
||||
}
|
||||
});
|
||||
@Override
|
||||
public void onPresenceSelected() {
|
||||
message.setCounterpart(conversation.getNextCounterpart());
|
||||
xmppService.sendMessage(message);
|
||||
messageSent();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
public void appendText(String text) {
|
||||
|
|
296
src/main/java/eu/siacs/conversations/ui/VerifyOTRActivity.java
Normal file
296
src/main/java/eu/siacs/conversations/ui/VerifyOTRActivity.java
Normal file
|
@ -0,0 +1,296 @@
|
|||
package eu.siacs.conversations.ui;
|
||||
|
||||
import android.content.Intent;
|
||||
import android.os.Bundle;
|
||||
import android.view.View;
|
||||
import android.widget.Button;
|
||||
import android.widget.EditText;
|
||||
import android.widget.RelativeLayout;
|
||||
import android.widget.TextView;
|
||||
import android.widget.Toast;
|
||||
|
||||
import net.java.otr4j.OtrException;
|
||||
import net.java.otr4j.session.Session;
|
||||
|
||||
import eu.siacs.conversations.R;
|
||||
import eu.siacs.conversations.entities.Account;
|
||||
import eu.siacs.conversations.entities.Conversation;
|
||||
import eu.siacs.conversations.services.XmppConnectionService;
|
||||
import eu.siacs.conversations.xmpp.jid.InvalidJidException;
|
||||
import eu.siacs.conversations.xmpp.jid.Jid;
|
||||
|
||||
public class VerifyOTRActivity extends XmppActivity implements XmppConnectionService.OnConversationUpdate {
|
||||
|
||||
public static final String ACTION_VERIFY_CONTACT = "verify_contact";
|
||||
|
||||
private RelativeLayout mVerificationAreaOne;
|
||||
private RelativeLayout mVerificationAreaTwo;
|
||||
private TextView mErrorNoSession;
|
||||
private TextView mRemoteJid;
|
||||
private TextView mRemoteFingerprint;
|
||||
private TextView mYourFingerprint;
|
||||
private EditText mSharedSecretHint;
|
||||
private EditText mSharedSecretSecret;
|
||||
private Button mButtonVerifyFingerprint;
|
||||
private Button mButtonSharedSecretPositive;
|
||||
private Button mButtonSharedSecretNegative;
|
||||
private TextView mStatusMessage;
|
||||
private Account mAccount;
|
||||
private Conversation mConversation;
|
||||
|
||||
private View.OnClickListener mVerifyFingerprintListener = new View.OnClickListener() {
|
||||
|
||||
@Override
|
||||
public void onClick(View view) {
|
||||
mConversation.verifyOtrFingerprint();
|
||||
finish();
|
||||
}
|
||||
};
|
||||
|
||||
private View.OnClickListener mCreateSharedSecretListener = new View.OnClickListener() {
|
||||
@Override
|
||||
public void onClick(final View view) {
|
||||
if (isAccountOnline()) {
|
||||
final String question = mSharedSecretHint.getText().toString();
|
||||
final String secret = mSharedSecretSecret.getText().toString();
|
||||
initSmp(question, secret);
|
||||
updateView();
|
||||
}
|
||||
}
|
||||
};
|
||||
private View.OnClickListener mCancelSharedSecretListener = new View.OnClickListener() {
|
||||
@Override
|
||||
public void onClick(View view) {
|
||||
if (isAccountOnline()) {
|
||||
abortSmp();
|
||||
updateView();
|
||||
}
|
||||
}
|
||||
};
|
||||
private View.OnClickListener mRespondSharedSecretListener = new View.OnClickListener() {
|
||||
|
||||
@Override
|
||||
public void onClick(View view) {
|
||||
if (isAccountOnline()) {
|
||||
final String question = mSharedSecretHint.getText().toString();
|
||||
final String secret = mSharedSecretSecret.getText().toString();
|
||||
respondSmp(question, secret);
|
||||
updateView();
|
||||
}
|
||||
}
|
||||
};
|
||||
private View.OnClickListener mRetrySharedSecretListener = new View.OnClickListener() {
|
||||
@Override
|
||||
public void onClick(View view) {
|
||||
mConversation.smp().status = Conversation.Smp.STATUS_NONE;
|
||||
mConversation.smp().hint = null;
|
||||
mConversation.smp().secret = null;
|
||||
updateView();
|
||||
}
|
||||
};
|
||||
private View.OnClickListener mFinishListener = new View.OnClickListener() {
|
||||
@Override
|
||||
public void onClick(View view) {
|
||||
mConversation.smp().status = Conversation.Smp.STATUS_NONE;
|
||||
finish();
|
||||
}
|
||||
};
|
||||
|
||||
protected boolean initSmp(final String question, final String secret) {
|
||||
final Session session = mConversation.getOtrSession();
|
||||
if (session!=null) {
|
||||
try {
|
||||
session.initSmp(question, secret);
|
||||
mConversation.smp().status = Conversation.Smp.STATUS_WE_REQUESTED;
|
||||
return true;
|
||||
} catch (OtrException e) {
|
||||
return false;
|
||||
}
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
protected boolean abortSmp() {
|
||||
final Session session = mConversation.getOtrSession();
|
||||
if (session!=null) {
|
||||
try {
|
||||
session.abortSmp();
|
||||
mConversation.smp().status = Conversation.Smp.STATUS_NONE;
|
||||
mConversation.smp().hint = null;
|
||||
mConversation.smp().secret = null;
|
||||
return true;
|
||||
} catch (OtrException e) {
|
||||
return false;
|
||||
}
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
protected boolean respondSmp(final String question, final String secret) {
|
||||
final Session session = mConversation.getOtrSession();
|
||||
if (session!=null) {
|
||||
try {
|
||||
session.respondSmp(question,secret);
|
||||
return true;
|
||||
} catch (OtrException e) {
|
||||
return false;
|
||||
}
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
protected boolean isAccountOnline() {
|
||||
if (this.mAccount.getStatus() != Account.STATUS_ONLINE) {
|
||||
Toast.makeText(this,R.string.not_connected_try_again,Toast.LENGTH_SHORT).show();
|
||||
return false;
|
||||
} else {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
protected boolean handleIntent(Intent intent) {
|
||||
if (intent.getAction().equals(ACTION_VERIFY_CONTACT)) {
|
||||
try {
|
||||
this.mAccount = this.xmppConnectionService.findAccountByJid(Jid.fromString(intent.getExtras().getString("account")));
|
||||
} catch (final InvalidJidException ignored) {
|
||||
return false;
|
||||
}
|
||||
try {
|
||||
this.mConversation = this.xmppConnectionService.find(this.mAccount,Jid.fromString(intent.getExtras().getString("contact")));
|
||||
if (this.mConversation == null) {
|
||||
return false;
|
||||
}
|
||||
} catch (final InvalidJidException ignored) {
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onBackendConnected() {
|
||||
if (handleIntent(getIntent())) {
|
||||
updateView();
|
||||
}
|
||||
}
|
||||
|
||||
protected void updateView() {
|
||||
if (this.mConversation.hasValidOtrSession()) {
|
||||
this.mVerificationAreaOne.setVisibility(View.VISIBLE);
|
||||
this.mVerificationAreaTwo.setVisibility(View.VISIBLE);
|
||||
this.mErrorNoSession.setVisibility(View.GONE);
|
||||
this.mYourFingerprint.setText(this.mAccount.getOtrFingerprint(xmppConnectionService));
|
||||
this.mRemoteFingerprint.setText(this.mConversation.getOtrFingerprint());
|
||||
this.mRemoteJid.setText(this.mConversation.getContact().getJid().toBareJid().toString());
|
||||
Conversation.Smp smp = mConversation.smp();
|
||||
Session session = mConversation.getOtrSession();
|
||||
if (mConversation.isOtrFingerprintVerified()) {
|
||||
deactivateButton(mButtonVerifyFingerprint, R.string.verified);
|
||||
} else {
|
||||
activateButton(mButtonVerifyFingerprint, R.string.verify, mVerifyFingerprintListener);
|
||||
}
|
||||
if (smp.status == Conversation.Smp.STATUS_NONE) {
|
||||
activateButton(mButtonSharedSecretPositive, R.string.create, mCreateSharedSecretListener);
|
||||
deactivateButton(mButtonSharedSecretNegative, R.string.cancel);
|
||||
this.mSharedSecretHint.setFocusableInTouchMode(true);
|
||||
this.mSharedSecretSecret.setFocusableInTouchMode(true);
|
||||
this.mSharedSecretSecret.setText("");
|
||||
this.mSharedSecretHint.setText("");
|
||||
this.mSharedSecretHint.setVisibility(View.VISIBLE);
|
||||
this.mSharedSecretSecret.setVisibility(View.VISIBLE);
|
||||
this.mStatusMessage.setVisibility(View.GONE);
|
||||
} else if (smp.status == Conversation.Smp.STATUS_CONTACT_REQUESTED) {
|
||||
this.mSharedSecretHint.setFocusable(false);
|
||||
this.mSharedSecretHint.setText(smp.hint);
|
||||
this.mSharedSecretSecret.setFocusableInTouchMode(true);
|
||||
this.mSharedSecretHint.setVisibility(View.VISIBLE);
|
||||
this.mSharedSecretSecret.setVisibility(View.VISIBLE);
|
||||
this.mStatusMessage.setVisibility(View.GONE);
|
||||
deactivateButton(mButtonSharedSecretNegative, R.string.cancel);
|
||||
activateButton(mButtonSharedSecretPositive, R.string.respond, mRespondSharedSecretListener);
|
||||
} else if (smp.status == Conversation.Smp.STATUS_FAILED) {
|
||||
activateButton(mButtonSharedSecretNegative, R.string.cancel, mFinishListener);
|
||||
activateButton(mButtonSharedSecretPositive, R.string.try_again, mRetrySharedSecretListener);
|
||||
this.mSharedSecretHint.setVisibility(View.GONE);
|
||||
this.mSharedSecretSecret.setVisibility(View.GONE);
|
||||
this.mStatusMessage.setVisibility(View.VISIBLE);
|
||||
this.mStatusMessage.setText(R.string.secrets_do_not_match);
|
||||
this.mStatusMessage.setTextColor(getWarningTextColor());
|
||||
} else if (smp.status == Conversation.Smp.STATUS_VERIFIED) {
|
||||
this.mSharedSecretHint.setVisibility(View.GONE);
|
||||
this.mSharedSecretSecret.setVisibility(View.GONE);
|
||||
this.mStatusMessage.setVisibility(View.VISIBLE);
|
||||
this.mStatusMessage.setText(R.string.verified);
|
||||
this.mStatusMessage.setTextColor(getPrimaryColor());
|
||||
deactivateButton(mButtonSharedSecretNegative, R.string.cancel);
|
||||
activateButton(mButtonSharedSecretPositive, R.string.finish, mFinishListener);
|
||||
} else if (session != null && session.isSmpInProgress()) {
|
||||
deactivateButton(mButtonSharedSecretPositive, R.string.in_progress);
|
||||
activateButton(mButtonSharedSecretNegative, R.string.cancel, mCancelSharedSecretListener);
|
||||
this.mSharedSecretHint.setVisibility(View.VISIBLE);
|
||||
this.mSharedSecretSecret.setVisibility(View.VISIBLE);
|
||||
this.mSharedSecretHint.setFocusable(false);
|
||||
this.mSharedSecretSecret.setFocusable(false);
|
||||
}
|
||||
} else {
|
||||
this.mVerificationAreaOne.setVisibility(View.GONE);
|
||||
this.mVerificationAreaTwo.setVisibility(View.GONE);
|
||||
this.mErrorNoSession.setVisibility(View.VISIBLE);
|
||||
}
|
||||
}
|
||||
|
||||
protected void activateButton(Button button, int text, View.OnClickListener listener) {
|
||||
button.setEnabled(true);
|
||||
button.setTextColor(getPrimaryTextColor());
|
||||
button.setText(text);
|
||||
button.setOnClickListener(listener);
|
||||
}
|
||||
|
||||
protected void deactivateButton(Button button, int text) {
|
||||
button.setEnabled(false);
|
||||
button.setTextColor(getSecondaryTextColor());
|
||||
button.setText(text);
|
||||
button.setOnClickListener(null);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onCreate(Bundle savedInstanceState) {
|
||||
super.onCreate(savedInstanceState);
|
||||
setContentView(R.layout.activity_verify_otr);
|
||||
this.mRemoteFingerprint = (TextView) findViewById(R.id.remote_fingerprint);
|
||||
this.mRemoteJid = (TextView) findViewById(R.id.remote_jid);
|
||||
this.mYourFingerprint = (TextView) findViewById(R.id.your_fingerprint);
|
||||
this.mButtonSharedSecretNegative = (Button) findViewById(R.id.button_shared_secret_negative);
|
||||
this.mButtonSharedSecretPositive = (Button) findViewById(R.id.button_shared_secret_positive);
|
||||
this.mButtonVerifyFingerprint = (Button) findViewById(R.id.button_verify_fingerprint);
|
||||
this.mSharedSecretSecret = (EditText) findViewById(R.id.shared_secret_secret);
|
||||
this.mSharedSecretHint = (EditText) findViewById(R.id.shared_secret_hint);
|
||||
this.mStatusMessage= (TextView) findViewById(R.id.status_message);
|
||||
this.mVerificationAreaOne = (RelativeLayout) findViewById(R.id.verification_area_one);
|
||||
this.mVerificationAreaTwo = (RelativeLayout) findViewById(R.id.verification_area_two);
|
||||
this.mErrorNoSession = (TextView) findViewById(R.id.error_no_session);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected String getShareableUri() {
|
||||
if (mAccount!=null) {
|
||||
return "xmpp:"+mAccount.getJid().toBareJid();
|
||||
} else {
|
||||
return "";
|
||||
}
|
||||
}
|
||||
|
||||
public void onConversationUpdate() {
|
||||
runOnUiThread(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
updateView();
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
|
@ -685,6 +685,7 @@ public abstract class XmppActivity extends Activity {
|
|||
}
|
||||
|
||||
protected Bitmap createQrCodeBitmap(String input, int size) {
|
||||
Log.d(Config.LOGTAG,"qr code requested size: "+size);
|
||||
try {
|
||||
final QRCodeWriter QR_CODE_WRITER = new QRCodeWriter();
|
||||
final Hashtable<EncodeHintType, Object> hints = new Hashtable<>();
|
||||
|
@ -700,6 +701,7 @@ public abstract class XmppActivity extends Activity {
|
|||
}
|
||||
}
|
||||
final Bitmap bitmap = Bitmap.createBitmap(width, height, Bitmap.Config.ARGB_8888);
|
||||
Log.d(Config.LOGTAG,"output size: "+width+"x"+height);
|
||||
bitmap.setPixels(pixels, 0, width, 0, 0, width, height);
|
||||
return bitmap;
|
||||
} catch (final WriterException e) {
|
||||
|
|
|
@ -148,40 +148,6 @@ public class UIHelper {
|
|||
mNotificationManager.notify(1111, notification);
|
||||
}
|
||||
|
||||
@SuppressLint("InflateParams")
|
||||
public static AlertDialog getVerifyFingerprintDialog(
|
||||
final ConversationActivity activity,
|
||||
final Conversation conversation, final View msg) {
|
||||
final Contact contact = conversation.getContact();
|
||||
final Account account = conversation.getAccount();
|
||||
|
||||
AlertDialog.Builder builder = new AlertDialog.Builder(activity);
|
||||
builder.setTitle("Verify fingerprint");
|
||||
LayoutInflater inflater = activity.getLayoutInflater();
|
||||
View view = inflater.inflate(R.layout.dialog_verify_otr, null);
|
||||
TextView jid = (TextView) view.findViewById(R.id.verify_otr_jid);
|
||||
TextView fingerprint = (TextView) view
|
||||
.findViewById(R.id.verify_otr_fingerprint);
|
||||
TextView yourprint = (TextView) view
|
||||
.findViewById(R.id.verify_otr_yourprint);
|
||||
|
||||
jid.setText(contact.getJid().toString());
|
||||
fingerprint.setText(conversation.getOtrFingerprint());
|
||||
yourprint.setText(account.getOtrFingerprint());
|
||||
builder.setNegativeButton("Cancel", null);
|
||||
builder.setPositiveButton("Verify", new OnClickListener() {
|
||||
|
||||
@Override
|
||||
public void onClick(DialogInterface dialog, int which) {
|
||||
contact.addOtrFingerprint(conversation.getOtrFingerprint());
|
||||
msg.setVisibility(View.GONE);
|
||||
activity.xmppConnectionService.syncRosterToDisk(account);
|
||||
}
|
||||
});
|
||||
builder.setView(view);
|
||||
return builder.create();
|
||||
}
|
||||
|
||||
private final static class EmoticonPattern {
|
||||
Pattern pattern;
|
||||
String replacement;
|
||||
|
|
189
src/main/res/layout/activity_verify_otr.xml
Normal file
189
src/main/res/layout/activity_verify_otr.xml
Normal file
|
@ -0,0 +1,189 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<ScrollView xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:layout_width="fill_parent"
|
||||
android:layout_height="fill_parent"
|
||||
android:background="@color/secondarybackground">
|
||||
|
||||
<LinearLayout
|
||||
android:layout_width="fill_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:orientation="vertical">
|
||||
<TextView
|
||||
android:id="@+id/error_no_session"
|
||||
android:layout_margin="16dp"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:text="@string/no_otr_session_found"
|
||||
android:layout_gravity="center_horizontal"
|
||||
android:textColor="@color/primarytext"
|
||||
android:textSize="?attr/TextSizeBody"
|
||||
/>
|
||||
<RelativeLayout
|
||||
android:id="@+id/verification_area_one"
|
||||
android:layout_width="fill_parent"
|
||||
android:layout_height="fill_parent"
|
||||
android:background="@drawable/infocard_border"
|
||||
android:layout_margin="8dp">
|
||||
<LinearLayout
|
||||
android:id="@+id/fingerprint_area"
|
||||
android:layout_width="fill_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:padding="16dp"
|
||||
android:orientation="vertical">
|
||||
<TextView
|
||||
android:id="@+id/remote_jid"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:textColor="@color/primarytext"
|
||||
android:textSize="?attr/TextSizeHeadline"/>
|
||||
<TextView
|
||||
android:layout_marginTop="16dp"
|
||||
android:id="@+id/your_fingerprint"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:textColor="@color/primarytext"
|
||||
android:textSize="?attr/TextSizeBody"
|
||||
android:typeface="monospace" />
|
||||
|
||||
<TextView
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:textColor="@color/secondarytext"
|
||||
android:textSize="?attr/TextSizeInfo"
|
||||
android:text="@string/your_fingerprint"/>
|
||||
<TextView
|
||||
android:layout_marginTop="16dp"
|
||||
android:id="@+id/remote_fingerprint"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:textColor="@color/primarytext"
|
||||
android:textSize="?attr/TextSizeBody"
|
||||
android:typeface="monospace" />
|
||||
|
||||
<TextView
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:textColor="@color/secondarytext"
|
||||
android:textSize="?attr/TextSizeInfo"
|
||||
android:text="@string/remote_fingerprint"/>
|
||||
</LinearLayout>
|
||||
<LinearLayout
|
||||
android:layout_below="@+id/fingerprint_area"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_alignParentBottom="true"
|
||||
android:layout_alignParentLeft="true"
|
||||
android:layout_alignParentRight="true" >
|
||||
|
||||
<Button
|
||||
style="?android:attr/borderlessButtonStyle"
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_weight="1"
|
||||
android:visibility="invisible" />
|
||||
|
||||
<View
|
||||
android:layout_width="1dp"
|
||||
android:layout_height="fill_parent"
|
||||
android:layout_marginBottom="7dp"
|
||||
android:layout_marginTop="7dp"
|
||||
android:background="@color/divider"
|
||||
android:visibility="invisible"/>
|
||||
|
||||
<Button
|
||||
android:id="@+id/button_verify_fingerprint"
|
||||
style="?android:attr/borderlessButtonStyle"
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_weight="1"
|
||||
android:text="@string/verify"
|
||||
android:textColor="@color/primarytext" />
|
||||
</LinearLayout>
|
||||
</RelativeLayout>
|
||||
<RelativeLayout
|
||||
android:id="@+id/verification_area_two"
|
||||
android:layout_width="fill_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_margin="8dp"
|
||||
android:background="@drawable/infocard_border">
|
||||
<LinearLayout
|
||||
android:layout_width="fill_parent"
|
||||
android:layout_height="fill_parent"
|
||||
android:orientation="vertical"
|
||||
android:id="@+id/shared_secret_box"
|
||||
android:padding="16dp">
|
||||
<TextView
|
||||
android:text="@string/smp"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:textColor="@color/primarytext"
|
||||
android:textSize="?attr/TextSizeHeadline"
|
||||
android:layout_marginBottom="16dp"
|
||||
/>
|
||||
<TextView
|
||||
android:id="@+id/status_message"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:text="@string/verified"
|
||||
android:layout_gravity="center_horizontal"
|
||||
android:textSize="?attr/TextSizeHeadline"
|
||||
android:textStyle="bold"
|
||||
android:visibility="gone"/>
|
||||
<EditText
|
||||
android:id="@+id/shared_secret_hint"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:inputType="textAutoComplete"
|
||||
android:hint="@string/shared_secret_hint"
|
||||
android:textColor="@color/primarytext"
|
||||
android:textColorHint="@color/secondarytext"
|
||||
android:textSize="?attr/TextSizeBody"
|
||||
android:layout_marginBottom="8dp"/>
|
||||
<EditText
|
||||
android:id="@+id/shared_secret_secret"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:hint="@string/shared_secret_secret"
|
||||
android:inputType="textPassword"
|
||||
android:textColor="@color/primarytext"
|
||||
android:textColorHint="@color/secondarytext"
|
||||
android:textSize="?attr/TextSizeBody" />
|
||||
</LinearLayout>
|
||||
<LinearLayout
|
||||
android:layout_below="@+id/shared_secret_box"
|
||||
android:id="@+id/button_bar"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_alignParentBottom="true"
|
||||
android:layout_alignParentLeft="true"
|
||||
android:layout_alignParentRight="true" >
|
||||
|
||||
<Button
|
||||
android:id="@+id/button_shared_secret_negative"
|
||||
style="?android:attr/borderlessButtonStyle"
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_weight="1"
|
||||
android:enabled="false"
|
||||
android:text="@string/cancel"
|
||||
android:textColor="@color/secondarytext"/>
|
||||
|
||||
<View
|
||||
android:layout_width="1dp"
|
||||
android:layout_height="fill_parent"
|
||||
android:layout_marginBottom="7dp"
|
||||
android:layout_marginTop="7dp"
|
||||
android:background="@color/divider" />
|
||||
|
||||
<Button
|
||||
android:id="@+id/button_shared_secret_positive"
|
||||
style="?android:attr/borderlessButtonStyle"
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_weight="1"
|
||||
android:text="@string/create"
|
||||
android:textColor="@color/primarytext" />
|
||||
</LinearLayout>
|
||||
</RelativeLayout>
|
||||
</LinearLayout>
|
||||
</ScrollView>
|
|
@ -1,60 +0,0 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
android:orientation="vertical"
|
||||
android:paddingBottom="16dp"
|
||||
android:paddingLeft="8dp"
|
||||
android:paddingRight="8dp" >
|
||||
|
||||
<TextView
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:paddingTop="8dp"
|
||||
android:text="@string/account_settings_jabber_id"
|
||||
android:textColor="@color/primarytext"
|
||||
android:textSize="?attr/TextSizeHeadline" />
|
||||
|
||||
<TextView
|
||||
android:id="@+id/verify_otr_jid"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:paddingLeft="8dp"
|
||||
android:textColor="@color/secondarytext"
|
||||
android:textSize="?attr/TextSizeBody" />
|
||||
|
||||
<TextView
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:paddingTop="8dp"
|
||||
android:text="@string/otr_fingerprint"
|
||||
android:textColor="@color/primarytext"
|
||||
android:textSize="?attr/TextSizeHeadline" />
|
||||
|
||||
<TextView
|
||||
android:id="@+id/verify_otr_fingerprint"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:paddingLeft="8dp"
|
||||
android:textColor="@color/secondarytext"
|
||||
android:textSize="?attr/TextSizeBody"
|
||||
android:typeface="monospace" />
|
||||
|
||||
<TextView
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:paddingTop="8dp"
|
||||
android:text="@string/your_fingerprint"
|
||||
android:textColor="@color/primarytext"
|
||||
android:textSize="?attr/TextSizeHeadline" />
|
||||
|
||||
<TextView
|
||||
android:id="@+id/verify_otr_yourprint"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:paddingLeft="8dp"
|
||||
android:textColor="@color/secondarytext"
|
||||
android:textSize="?attr/TextSizeBody"
|
||||
android:typeface="monospace" />
|
||||
|
||||
</LinearLayout>
|
|
@ -311,4 +311,21 @@
|
|||
<string name="scan_qr_code">Scan QR code</string>
|
||||
<string name="show_qr_code">Show QR code</string>
|
||||
<string name="account_details">Account details</string>
|
||||
<string name="verify_otr">Verify OTR</string>
|
||||
<string name="remote_fingerprint">Remote Fingerprint</string>
|
||||
<string name="scan">scan</string>
|
||||
<string name="or_touch_phones">(or touch phones)</string>
|
||||
<string name="smp">Socialist Millionaire Protocol</string>
|
||||
<string name="shared_secret_hint">Hint or Question</string>
|
||||
<string name="shared_secret_secret">Shared Secret</string>
|
||||
<string name="confirm">Confirm</string>
|
||||
<string name="in_progress">In progress</string>
|
||||
<string name="respond">Respond</string>
|
||||
<string name="failed">Failed</string>
|
||||
<string name="secrets_do_not_match">Secrets do not match</string>
|
||||
<string name="try_again">Try again</string>;
|
||||
<string name="finish">Finish</string>
|
||||
<string name="verified">Verified!</string>
|
||||
<string name="smp_requested">Contact requested SMP verification</string>
|
||||
<string name="no_otr_session_found">No valid OTR session has been found!</string>
|
||||
</resources>
|
||||
|
|
Loading…
Reference in a new issue