2015-01-15 13:35:35 -08:00
|
|
|
package org.thoughtcrime.securesms;
|
|
|
|
|
2018-01-24 19:17:44 -08:00
|
|
|
import android.annotation.SuppressLint;
|
2015-01-15 13:35:35 -08:00
|
|
|
import android.content.Context;
|
|
|
|
import android.content.DialogInterface;
|
|
|
|
import android.database.Cursor;
|
|
|
|
import android.os.AsyncTask;
|
2020-08-19 10:06:26 +10:00
|
|
|
import androidx.appcompat.app.AlertDialog;
|
2015-01-15 13:35:35 -08:00
|
|
|
import android.text.SpannableString;
|
|
|
|
import android.text.Spanned;
|
|
|
|
import android.text.method.LinkMovementMethod;
|
|
|
|
import android.widget.TextView;
|
|
|
|
|
2017-05-19 18:01:40 -07:00
|
|
|
import org.thoughtcrime.securesms.crypto.storage.TextSecureIdentityKeyStore;
|
2017-07-26 09:59:15 -07:00
|
|
|
import org.thoughtcrime.securesms.database.Address;
|
2015-01-15 13:35:35 -08:00
|
|
|
import org.thoughtcrime.securesms.database.DatabaseFactory;
|
|
|
|
import org.thoughtcrime.securesms.database.MmsDatabase;
|
|
|
|
import org.thoughtcrime.securesms.database.MmsSmsDatabase;
|
|
|
|
import org.thoughtcrime.securesms.database.PushDatabase;
|
|
|
|
import org.thoughtcrime.securesms.database.SmsDatabase;
|
|
|
|
import org.thoughtcrime.securesms.database.documents.IdentityKeyMismatch;
|
|
|
|
import org.thoughtcrime.securesms.database.model.MessageRecord;
|
|
|
|
import org.thoughtcrime.securesms.jobs.PushDecryptJob;
|
|
|
|
import org.thoughtcrime.securesms.recipients.Recipient;
|
|
|
|
import org.thoughtcrime.securesms.sms.MessageSender;
|
|
|
|
import org.thoughtcrime.securesms.util.Base64;
|
2016-11-09 09:37:40 -08:00
|
|
|
import org.thoughtcrime.securesms.util.VerifySpan;
|
2017-05-19 18:01:40 -07:00
|
|
|
import org.whispersystems.libsignal.SignalProtocolAddress;
|
2016-03-23 10:34:41 -07:00
|
|
|
import org.whispersystems.signalservice.api.messages.SignalServiceEnvelope;
|
|
|
|
import org.whispersystems.signalservice.internal.push.SignalServiceProtos;
|
2015-01-15 13:35:35 -08:00
|
|
|
|
|
|
|
import java.io.IOException;
|
|
|
|
|
2019-07-24 12:30:23 +10:00
|
|
|
import network.loki.messenger.R;
|
|
|
|
|
2017-05-19 18:01:40 -07:00
|
|
|
import static org.whispersystems.libsignal.SessionCipher.SESSION_LOCK;
|
|
|
|
|
2015-01-15 13:35:35 -08:00
|
|
|
public class ConfirmIdentityDialog extends AlertDialog {
|
|
|
|
|
2018-01-24 19:17:44 -08:00
|
|
|
@SuppressWarnings("unused")
|
2015-01-15 13:35:35 -08:00
|
|
|
private static final String TAG = ConfirmIdentityDialog.class.getSimpleName();
|
|
|
|
|
|
|
|
private OnClickListener callback;
|
|
|
|
|
|
|
|
public ConfirmIdentityDialog(Context context,
|
|
|
|
MessageRecord messageRecord,
|
|
|
|
IdentityKeyMismatch mismatch)
|
|
|
|
{
|
|
|
|
super(context);
|
|
|
|
|
2017-08-21 18:32:38 -07:00
|
|
|
Recipient recipient = Recipient.from(context, mismatch.getAddress(), false);
|
2017-02-19 12:29:08 -08:00
|
|
|
String name = recipient.toShortString();
|
2019-05-08 08:45:57 -03:00
|
|
|
String introduction = context.getString(R.string.ConfirmIdentityDialog_your_safety_number_with_s_has_changed, name, name);
|
2017-02-19 12:29:08 -08:00
|
|
|
SpannableString spannableString = new SpannableString(introduction + " " +
|
|
|
|
context.getString(R.string.ConfirmIdentityDialog_you_may_wish_to_verify_your_safety_number_with_this_contact));
|
|
|
|
|
|
|
|
spannableString.setSpan(new VerifySpan(context, mismatch),
|
|
|
|
introduction.length()+1, spannableString.length(),
|
|
|
|
Spanned.SPAN_EXCLUSIVE_EXCLUSIVE);
|
|
|
|
|
|
|
|
setTitle(name);
|
|
|
|
setMessage(spannableString);
|
|
|
|
|
2018-01-24 19:17:44 -08:00
|
|
|
setButton(AlertDialog.BUTTON_POSITIVE, context.getString(R.string.ConfirmIdentityDialog_accept), new AcceptListener(messageRecord, mismatch, recipient.getAddress()));
|
2017-02-19 12:29:08 -08:00
|
|
|
setButton(AlertDialog.BUTTON_NEGATIVE, context.getString(android.R.string.cancel), new CancelListener());
|
2015-01-15 13:35:35 -08:00
|
|
|
}
|
|
|
|
|
|
|
|
@Override
|
|
|
|
public void show() {
|
|
|
|
super.show();
|
|
|
|
((TextView)this.findViewById(android.R.id.message))
|
|
|
|
.setMovementMethod(LinkMovementMethod.getInstance());
|
|
|
|
}
|
|
|
|
|
|
|
|
public void setCallback(OnClickListener callback) {
|
|
|
|
this.callback = callback;
|
|
|
|
}
|
|
|
|
|
|
|
|
private class AcceptListener implements OnClickListener {
|
|
|
|
|
|
|
|
private final MessageRecord messageRecord;
|
|
|
|
private final IdentityKeyMismatch mismatch;
|
2017-07-26 09:59:15 -07:00
|
|
|
private final Address address;
|
2015-01-15 13:35:35 -08:00
|
|
|
|
2018-01-24 19:17:44 -08:00
|
|
|
private AcceptListener(MessageRecord messageRecord, IdentityKeyMismatch mismatch, Address address) {
|
2015-01-15 13:35:35 -08:00
|
|
|
this.messageRecord = messageRecord;
|
|
|
|
this.mismatch = mismatch;
|
2017-07-26 09:59:15 -07:00
|
|
|
this.address = address;
|
2015-01-15 13:35:35 -08:00
|
|
|
}
|
|
|
|
|
2018-01-24 19:17:44 -08:00
|
|
|
@SuppressLint("StaticFieldLeak")
|
2015-01-15 13:35:35 -08:00
|
|
|
@Override
|
|
|
|
public void onClick(DialogInterface dialog, int which) {
|
|
|
|
new AsyncTask<Void, Void, Void>()
|
|
|
|
{
|
|
|
|
@Override
|
|
|
|
protected Void doInBackground(Void... params) {
|
2017-05-19 18:01:40 -07:00
|
|
|
synchronized (SESSION_LOCK) {
|
2017-07-26 09:59:15 -07:00
|
|
|
SignalProtocolAddress mismatchAddress = new SignalProtocolAddress(address.toPhoneString(), 1);
|
2017-05-30 18:30:37 -07:00
|
|
|
TextSecureIdentityKeyStore identityKeyStore = new TextSecureIdentityKeyStore(getContext());
|
2015-01-15 13:35:35 -08:00
|
|
|
|
2017-06-06 18:03:09 -07:00
|
|
|
identityKeyStore.saveIdentity(mismatchAddress, mismatch.getIdentityKey(), true);
|
2017-05-19 18:01:40 -07:00
|
|
|
}
|
2017-02-19 12:29:08 -08:00
|
|
|
|
2015-01-15 13:35:35 -08:00
|
|
|
processMessageRecord(messageRecord);
|
|
|
|
processPendingMessageRecords(messageRecord.getThreadId(), mismatch);
|
|
|
|
|
|
|
|
return null;
|
|
|
|
}
|
|
|
|
|
|
|
|
private void processMessageRecord(MessageRecord messageRecord) {
|
|
|
|
if (messageRecord.isOutgoing()) processOutgoingMessageRecord(messageRecord);
|
|
|
|
else processIncomingMessageRecord(messageRecord);
|
|
|
|
}
|
|
|
|
|
|
|
|
private void processPendingMessageRecords(long threadId, IdentityKeyMismatch mismatch) {
|
|
|
|
MmsSmsDatabase mmsSmsDatabase = DatabaseFactory.getMmsSmsDatabase(getContext());
|
|
|
|
Cursor cursor = mmsSmsDatabase.getIdentityConflictMessagesForThread(threadId);
|
2018-01-24 19:17:44 -08:00
|
|
|
MmsSmsDatabase.Reader reader = mmsSmsDatabase.readerFor(cursor);
|
2015-01-15 13:35:35 -08:00
|
|
|
MessageRecord record;
|
|
|
|
|
|
|
|
try {
|
|
|
|
while ((record = reader.getNext()) != null) {
|
|
|
|
for (IdentityKeyMismatch recordMismatch : record.getIdentityKeyMismatches()) {
|
|
|
|
if (mismatch.equals(recordMismatch)) {
|
|
|
|
processMessageRecord(record);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
} finally {
|
|
|
|
if (reader != null)
|
|
|
|
reader.close();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
private void processOutgoingMessageRecord(MessageRecord messageRecord) {
|
|
|
|
SmsDatabase smsDatabase = DatabaseFactory.getSmsDatabase(getContext());
|
|
|
|
MmsDatabase mmsDatabase = DatabaseFactory.getMmsDatabase(getContext());
|
|
|
|
|
|
|
|
if (messageRecord.isMms()) {
|
|
|
|
mmsDatabase.removeMismatchedIdentity(messageRecord.getId(),
|
2017-07-26 09:59:15 -07:00
|
|
|
mismatch.getAddress(),
|
2015-01-15 13:35:35 -08:00
|
|
|
mismatch.getIdentityKey());
|
|
|
|
|
2017-08-01 08:56:00 -07:00
|
|
|
if (messageRecord.getRecipient().isPushGroupRecipient()) {
|
|
|
|
MessageSender.resendGroupMessage(getContext(), messageRecord, mismatch.getAddress());
|
|
|
|
} else {
|
2018-01-24 19:17:44 -08:00
|
|
|
MessageSender.resend(getContext(), messageRecord);
|
2017-08-01 08:56:00 -07:00
|
|
|
}
|
2015-01-15 13:35:35 -08:00
|
|
|
} else {
|
|
|
|
smsDatabase.removeMismatchedIdentity(messageRecord.getId(),
|
2017-07-26 09:59:15 -07:00
|
|
|
mismatch.getAddress(),
|
2015-01-15 13:35:35 -08:00
|
|
|
mismatch.getIdentityKey());
|
|
|
|
|
2018-01-24 19:17:44 -08:00
|
|
|
MessageSender.resend(getContext(), messageRecord);
|
2015-01-15 13:35:35 -08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
private void processIncomingMessageRecord(MessageRecord messageRecord) {
|
|
|
|
try {
|
|
|
|
PushDatabase pushDatabase = DatabaseFactory.getPushDatabase(getContext());
|
|
|
|
SmsDatabase smsDatabase = DatabaseFactory.getSmsDatabase(getContext());
|
|
|
|
|
|
|
|
smsDatabase.removeMismatchedIdentity(messageRecord.getId(),
|
2017-07-26 09:59:15 -07:00
|
|
|
mismatch.getAddress(),
|
2015-01-15 13:35:35 -08:00
|
|
|
mismatch.getIdentityKey());
|
|
|
|
|
2016-11-09 09:37:40 -08:00
|
|
|
boolean legacy = !messageRecord.isContentBundleKeyExchange();
|
|
|
|
|
2016-03-23 10:34:41 -07:00
|
|
|
SignalServiceEnvelope envelope = new SignalServiceEnvelope(SignalServiceProtos.Envelope.Type.PREKEY_BUNDLE_VALUE,
|
2017-07-26 09:59:15 -07:00
|
|
|
messageRecord.getIndividualRecipient().getAddress().toPhoneString(),
|
2018-05-22 02:13:10 -07:00
|
|
|
messageRecord.getRecipientDeviceId(),
|
2016-03-23 10:34:41 -07:00
|
|
|
messageRecord.getDateSent(),
|
2018-02-01 18:29:09 -08:00
|
|
|
legacy ? Base64.decode(messageRecord.getBody()) : null,
|
2018-05-22 02:13:10 -07:00
|
|
|
!legacy ? Base64.decode(messageRecord.getBody()) : null,
|
|
|
|
0, null);
|
2015-01-15 13:35:35 -08:00
|
|
|
|
|
|
|
long pushId = pushDatabase.insert(envelope);
|
|
|
|
|
|
|
|
ApplicationContext.getInstance(getContext())
|
|
|
|
.getJobManager()
|
2017-07-26 09:59:15 -07:00
|
|
|
.add(new PushDecryptJob(getContext(), pushId, messageRecord.getId()));
|
2015-01-15 13:35:35 -08:00
|
|
|
} catch (IOException e) {
|
|
|
|
throw new AssertionError(e);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2017-10-23 13:03:32 -07:00
|
|
|
}.executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR);
|
2015-01-15 13:35:35 -08:00
|
|
|
|
|
|
|
if (callback != null) callback.onClick(null, 0);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
private class CancelListener implements OnClickListener {
|
|
|
|
@Override
|
|
|
|
public void onClick(DialogInterface dialog, int which) {
|
|
|
|
if (callback != null) callback.onClick(null, 0);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
}
|