mirror of
https://github.com/oxen-io/session-android.git
synced 2025-02-19 19:08:26 +00:00
UX for unencrypted fallback case
This commit is contained in:
parent
40629a3bcf
commit
832763f695
@ -35,6 +35,27 @@ public class Session {
|
||||
return hasV1Session(context, recipient) || hasV2Session(context, masterSecret, recipient);
|
||||
}
|
||||
|
||||
public static boolean hasEncryptCapableSession(Context context,
|
||||
MasterSecret masterSecret,
|
||||
CanonicalRecipient recipient)
|
||||
{
|
||||
RecipientDevice device = new RecipientDevice(recipient.getRecipientId(),
|
||||
RecipientDevice.DEFAULT_DEVICE_ID);
|
||||
|
||||
return hasEncryptCapableSession(context, masterSecret, recipient, device);
|
||||
}
|
||||
|
||||
public static boolean hasEncryptCapableSession(Context context,
|
||||
MasterSecret masterSecret,
|
||||
CanonicalRecipient recipient,
|
||||
RecipientDevice device)
|
||||
{
|
||||
return
|
||||
hasV1Session(context, recipient) ||
|
||||
(hasV2Session(context, masterSecret, recipient) &&
|
||||
!SessionRecordV2.needsRefresh(context, masterSecret, device));
|
||||
}
|
||||
|
||||
public static boolean hasRemoteIdentityKey(Context context,
|
||||
MasterSecret masterSecret,
|
||||
CanonicalRecipient recipient)
|
||||
|
@ -64,7 +64,10 @@
|
||||
<string name="ConversationItem_group_action_joined">%1$s have joined the group.</string>
|
||||
<string name="ConversationItem_group_action_modify">%1$s has updated the group.</string>
|
||||
<string name="ConversationItem_click_to_approve">Tap for SMS fallback</string>
|
||||
<string name="ConversationItem_click_to_approve_unencrypted">Tap for insecure fallback</string>
|
||||
<string name="ConversationItem_click_to_approve_dialog_title">Fallback to SMS?</string>
|
||||
<string name="ConversationItem_click_to_approve_unencrypted_dialog_title">Fallback to unencrypted SMS?</string>
|
||||
<string name="ConversationItem_click_to_approve_unencrypted_dialog_message">This message will <b>not</b> be encrypted because a secure session could not be established.\n\nSend insecure message?</string>
|
||||
|
||||
<!-- ConversationActivity -->
|
||||
<string name="ConversationActivity_initiate_secure_session_question">Initiate Secure Session?</string>
|
||||
|
@ -675,7 +675,7 @@ public class ConversationActivity extends PassphraseRequiredSherlockFragmentActi
|
||||
R.attr.conversation_send_secure_button};
|
||||
TypedArray drawables = obtainStyledAttributes(attributes);
|
||||
|
||||
if ((getRecipients() != null && getRecipients().isGroupRecipient()) ||
|
||||
if (isPushDestination() || (getRecipients() != null && getRecipients().isGroupRecipient()) ||
|
||||
(isSingleConversation() && Session.hasSession(this, masterSecret, getRecipients().getPrimaryRecipient())))
|
||||
{
|
||||
sendButton.setImageDrawable(drawables.getDrawable(1));
|
||||
@ -1074,7 +1074,7 @@ public class ConversationActivity extends PassphraseRequiredSherlockFragmentActi
|
||||
|
||||
private void sendMessage(boolean forcePlaintext) {
|
||||
try {
|
||||
Recipients recipients = getRecipients();
|
||||
Recipients recipients = getRecipients();
|
||||
|
||||
if (recipients == null)
|
||||
throw new RecipientFormattingException("Badly formatted");
|
||||
|
@ -25,8 +25,6 @@ import android.content.res.TypedArray;
|
||||
import android.graphics.Color;
|
||||
import android.graphics.drawable.ColorDrawable;
|
||||
import android.media.MediaScannerConnection;
|
||||
import android.net.ConnectivityManager;
|
||||
import android.net.NetworkInfo;
|
||||
import android.net.Uri;
|
||||
import android.os.Build;
|
||||
import android.os.Environment;
|
||||
@ -59,8 +57,6 @@ import org.thoughtcrime.securesms.util.DateUtils;
|
||||
import org.thoughtcrime.securesms.util.Emoji;
|
||||
import org.thoughtcrime.securesms.util.Dialogs;
|
||||
import org.whispersystems.textsecure.crypto.MasterSecret;
|
||||
import org.whispersystems.textsecure.directory.Directory;
|
||||
import org.whispersystems.textsecure.directory.NotInDirectoryException;
|
||||
import org.whispersystems.textsecure.storage.Session;
|
||||
import org.whispersystems.textsecure.util.FutureTaskListener;
|
||||
import org.whispersystems.textsecure.util.ListenableFutureTask;
|
||||
@ -230,7 +226,7 @@ public class ConversationItem extends LinearLayout {
|
||||
if (messageRecord.isPending() && pushDestination && !messageRecord.isForcedSms()) {
|
||||
background = SENT_PUSH_PENDING;
|
||||
triangleBackground = SENT_PUSH_PENDING_TRIANGLE;
|
||||
} else if (messageRecord.isPending() || messageRecord.isPendingFallbackApproval()) {
|
||||
} else if (messageRecord.isPending() || messageRecord.isPendingSmsFallback()) {
|
||||
background = SENT_SMS_PENDING;
|
||||
triangleBackground = SENT_SMS_PENDING_TRIANGLE;
|
||||
} else if (messageRecord.isPush()) {
|
||||
@ -265,8 +261,8 @@ public class ConversationItem extends LinearLayout {
|
||||
private void setStatusIcons(MessageRecord messageRecord) {
|
||||
failedImage.setVisibility(messageRecord.isFailed() ? View.VISIBLE : View.GONE);
|
||||
if (messageRecord.isOutgoing()) {
|
||||
pendingIndicator.setVisibility(messageRecord.isPendingFallbackApproval() ? View.VISIBLE : View.GONE);
|
||||
indicatorText.setVisibility(messageRecord.isPendingFallbackApproval() ? View.VISIBLE : View.GONE);
|
||||
pendingIndicator.setVisibility(messageRecord.isPendingSmsFallback() ? View.VISIBLE : View.GONE);
|
||||
indicatorText.setVisibility(messageRecord.isPendingSmsFallback() ? View.VISIBLE : View.GONE);
|
||||
}
|
||||
secureImage.setVisibility(messageRecord.isSecure() ? View.VISIBLE : View.GONE);
|
||||
keyImage.setVisibility(messageRecord.isKeyExchange() ? View.VISIBLE : View.GONE);
|
||||
@ -278,9 +274,10 @@ public class ConversationItem extends LinearLayout {
|
||||
|
||||
if (messageRecord.isFailed()) {
|
||||
dateText.setText(R.string.ConversationItem_error_sending_message);
|
||||
} else if (messageRecord.isPendingFallbackApproval() && indicatorText != null) {
|
||||
} else if (messageRecord.isPendingSmsFallback() && indicatorText != null) {
|
||||
dateText.setText("");
|
||||
indicatorText.setText(R.string.ConversationItem_click_to_approve);
|
||||
if (messageRecord.isPendingSecureSmsFallback()) indicatorText.setText(R.string.ConversationItem_click_to_approve);
|
||||
else indicatorText.setText(R.string.ConversationItem_click_to_approve_unencrypted);
|
||||
} else if (messageRecord.isPending()) {
|
||||
dateText.setText(" ··· ");
|
||||
} else {
|
||||
@ -294,14 +291,15 @@ public class ConversationItem extends LinearLayout {
|
||||
|
||||
private void setMinimumWidth() {
|
||||
if (indicatorText != null && indicatorText.getVisibility() == View.VISIBLE && indicatorText.getText() != null) {
|
||||
conversationParent.setMinimumWidth(indicatorText.getText().length() * 20);
|
||||
final float density = getResources().getDisplayMetrics().density;
|
||||
conversationParent.setMinimumWidth(indicatorText.getText().length() * (int)(6.5 * density));
|
||||
} else {
|
||||
conversationParent.setMinimumWidth(0);
|
||||
}
|
||||
}
|
||||
|
||||
private void setEvents(MessageRecord messageRecord) {
|
||||
setClickable(messageRecord.isPendingFallbackApproval() ||
|
||||
setClickable(messageRecord.isPendingSmsFallback() ||
|
||||
(messageRecord.isKeyExchange() &&
|
||||
!messageRecord.isCorruptedKeyExchange() &&
|
||||
!messageRecord.isOutgoing()));
|
||||
@ -640,23 +638,40 @@ public class ConversationItem extends LinearLayout {
|
||||
!messageRecord.isProcessedKeyExchange() &&
|
||||
!messageRecord.isStaleKeyExchange())
|
||||
handleKeyExchangeClicked();
|
||||
else if (messageRecord.isPendingFallbackApproval())
|
||||
else if (messageRecord.isPendingSmsFallback())
|
||||
handleMessageApproval();
|
||||
}
|
||||
}
|
||||
|
||||
private void handleMessageApproval() {
|
||||
final int title;
|
||||
final int message;
|
||||
if (messageRecord.isPendingSecureSmsFallback()) {
|
||||
title = R.string.ConversationItem_click_to_approve_dialog_title;
|
||||
message = -1;
|
||||
} else {
|
||||
title = R.string.ConversationItem_click_to_approve_unencrypted_dialog_title;
|
||||
message = R.string.ConversationItem_click_to_approve_unencrypted_dialog_message;
|
||||
}
|
||||
|
||||
AlertDialog.Builder builder = new AlertDialog.Builder(context);
|
||||
builder.setTitle(R.string.ConversationItem_click_to_approve_dialog_title);
|
||||
builder.setTitle(title);
|
||||
if (message > -1) builder.setMessage(message);
|
||||
builder.setPositiveButton(R.string.yes, new DialogInterface.OnClickListener() {
|
||||
@Override
|
||||
public void onClick(DialogInterface dialogInterface, int i) {
|
||||
if (messageRecord.isMms()) {
|
||||
MmsDatabase database = DatabaseFactory.getMmsDatabase(context);
|
||||
if (messageRecord.isPendingInsecureSmsFallback()) {
|
||||
database.markAsInsecure(messageRecord.getId());
|
||||
}
|
||||
database.markAsOutbox(messageRecord.getId());
|
||||
database.markAsForcedSms(messageRecord.getId());
|
||||
} else {
|
||||
SmsDatabase database = DatabaseFactory.getSmsDatabase(context);
|
||||
if (messageRecord.isPendingInsecureSmsFallback()) {
|
||||
database.markAsInsecure(messageRecord.getId());
|
||||
}
|
||||
database.markAsOutbox(messageRecord.getId());
|
||||
database.markAsForcedSms(messageRecord.getId());
|
||||
}
|
||||
@ -669,8 +684,11 @@ public class ConversationItem extends LinearLayout {
|
||||
builder.setNegativeButton(R.string.no, new DialogInterface.OnClickListener() {
|
||||
@Override
|
||||
public void onClick(DialogInterface dialogInterface, int i) {
|
||||
if (messageRecord.isMms()) DatabaseFactory.getMmsDatabase(context).markAsSentFailed(messageRecord.getId());
|
||||
else DatabaseFactory.getSmsDatabase(context).markAsSentFailed(messageRecord.getId());
|
||||
if (messageRecord.isMms()) {
|
||||
DatabaseFactory.getMmsDatabase(context).markAsSentFailed(messageRecord.getId());
|
||||
} else {
|
||||
DatabaseFactory.getSmsDatabase(context).markAsSentFailed(messageRecord.getId());
|
||||
}
|
||||
}
|
||||
});
|
||||
builder.show();
|
||||
|
@ -285,8 +285,13 @@ public class MmsDatabase extends Database implements MmsSmsColumns {
|
||||
updateMailboxBitmask(id, 0, Types.MESSAGE_FORCE_SMS_BIT);
|
||||
}
|
||||
|
||||
public void markAsPendingApproval(long messageId) {
|
||||
updateMailboxBitmask(messageId, Types.BASE_TYPE_MASK, Types.BASE_PENDING_FALLBACK_APPROVAL);
|
||||
public void markAsPendingSecureSmsFallback(long messageId) {
|
||||
updateMailboxBitmask(messageId, Types.BASE_TYPE_MASK, Types.BASE_PENDING_SECURE_SMS_FALLBACK);
|
||||
notifyConversationListeners(getThreadIdForMessage(messageId));
|
||||
}
|
||||
|
||||
public void markAsPendingInsecureSmsFallback(long messageId) {
|
||||
updateMailboxBitmask(messageId, Types.BASE_TYPE_MASK, Types.BASE_PENDING_INSECURE_SMS_FALLBACK);
|
||||
notifyConversationListeners(getThreadIdForMessage(messageId));
|
||||
}
|
||||
|
||||
@ -338,6 +343,10 @@ public class MmsDatabase extends Database implements MmsSmsColumns {
|
||||
updateMailboxBitmask(messageId, 0, Types.SECURE_MESSAGE_BIT);
|
||||
}
|
||||
|
||||
public void markAsInsecure(long messageId) {
|
||||
updateMailboxBitmask(messageId, Types.SECURE_MESSAGE_BIT, 0);
|
||||
}
|
||||
|
||||
public void markAsPush(long messageId) {
|
||||
updateMailboxBitmask(messageId, 0, Types.PUSH_MESSAGE_BIT);
|
||||
}
|
||||
|
@ -15,18 +15,20 @@ public interface MmsSmsColumns {
|
||||
protected static final long TOTAL_MASK = 0xFFFFFFFF;
|
||||
|
||||
// Base Types
|
||||
protected static final long BASE_TYPE_MASK = 0x1F;
|
||||
protected static final long BASE_TYPE_MASK = 0x1F;
|
||||
|
||||
protected static final long BASE_INBOX_TYPE = 20;
|
||||
protected static final long BASE_OUTBOX_TYPE = 21;
|
||||
protected static final long BASE_SENDING_TYPE = 22;
|
||||
protected static final long BASE_SENT_TYPE = 23;
|
||||
protected static final long BASE_SENT_FAILED_TYPE = 24;
|
||||
protected static final long BASE_PENDING_FALLBACK_APPROVAL = 25;
|
||||
protected static final long BASE_INBOX_TYPE = 20;
|
||||
protected static final long BASE_OUTBOX_TYPE = 21;
|
||||
protected static final long BASE_SENDING_TYPE = 22;
|
||||
protected static final long BASE_SENT_TYPE = 23;
|
||||
protected static final long BASE_SENT_FAILED_TYPE = 24;
|
||||
protected static final long BASE_PENDING_SECURE_SMS_FALLBACK = 25;
|
||||
protected static final long BASE_PENDING_INSECURE_SMS_FALLBACK = 26;
|
||||
|
||||
protected static final long[] OUTGOING_MESSAGE_TYPES = {BASE_OUTBOX_TYPE, BASE_SENT_TYPE,
|
||||
BASE_SENDING_TYPE, BASE_SENT_FAILED_TYPE,
|
||||
BASE_PENDING_FALLBACK_APPROVAL};
|
||||
BASE_PENDING_SECURE_SMS_FALLBACK,
|
||||
BASE_PENDING_INSECURE_SMS_FALLBACK};
|
||||
|
||||
// Message attributes
|
||||
protected static final long MESSAGE_ATTRIBUTE_MASK = 0xE0;
|
||||
@ -82,8 +84,17 @@ public interface MmsSmsColumns {
|
||||
(type & BASE_TYPE_MASK) == BASE_SENDING_TYPE;
|
||||
}
|
||||
|
||||
public static boolean isPendingApprovalType(long type) {
|
||||
return (type & BASE_TYPE_MASK) == BASE_PENDING_FALLBACK_APPROVAL;
|
||||
public static boolean isPendingSmsFallbackType(long type) {
|
||||
return (type & BASE_TYPE_MASK) == BASE_PENDING_INSECURE_SMS_FALLBACK ||
|
||||
(type & BASE_TYPE_MASK) == BASE_PENDING_SECURE_SMS_FALLBACK;
|
||||
}
|
||||
|
||||
public static boolean isPendingSecureSmsFallbackType(long type) {
|
||||
return (type & BASE_TYPE_MASK) == BASE_PENDING_SECURE_SMS_FALLBACK;
|
||||
}
|
||||
|
||||
public static boolean isPendingInsecureSmsFallbackType(long type) {
|
||||
return (type & BASE_TYPE_MASK) == BASE_PENDING_INSECURE_SMS_FALLBACK;
|
||||
}
|
||||
|
||||
public static boolean isInboxType(long type) {
|
||||
|
@ -174,6 +174,10 @@ public class SmsDatabase extends Database implements MmsSmsColumns {
|
||||
updateTypeBitmask(id, 0, Types.SECURE_MESSAGE_BIT);
|
||||
}
|
||||
|
||||
public void markAsInsecure(long id) {
|
||||
updateTypeBitmask(id, Types.SECURE_MESSAGE_BIT, 0);
|
||||
}
|
||||
|
||||
public void markAsPush(long id) {
|
||||
updateTypeBitmask(id, 0, Types.PUSH_MESSAGE_BIT);
|
||||
}
|
||||
@ -202,8 +206,12 @@ public class SmsDatabase extends Database implements MmsSmsColumns {
|
||||
updateTypeBitmask(id, Types.BASE_TYPE_MASK, Types.BASE_OUTBOX_TYPE);
|
||||
}
|
||||
|
||||
public void markAsPendingApproval(long id) {
|
||||
updateTypeBitmask(id, Types.BASE_TYPE_MASK, Types.BASE_PENDING_FALLBACK_APPROVAL);
|
||||
public void markAsPendingSecureSmsFallback(long id) {
|
||||
updateTypeBitmask(id, Types.BASE_TYPE_MASK, Types.BASE_PENDING_SECURE_SMS_FALLBACK);
|
||||
}
|
||||
|
||||
public void markAsPendingInsecureSmsFallback(long id) {
|
||||
updateTypeBitmask(id, Types.BASE_TYPE_MASK, Types.BASE_PENDING_INSECURE_SMS_FALLBACK);
|
||||
}
|
||||
|
||||
public void markAsSending(long id) {
|
||||
|
@ -28,7 +28,6 @@ import org.thoughtcrime.securesms.database.SmsDatabase;
|
||||
import org.thoughtcrime.securesms.recipients.Recipient;
|
||||
import org.thoughtcrime.securesms.recipients.Recipients;
|
||||
import org.thoughtcrime.securesms.util.GroupUtil;
|
||||
import org.whispersystems.textsecure.util.Util;
|
||||
|
||||
/**
|
||||
* The base class for message record models that are displayed in
|
||||
@ -125,8 +124,16 @@ public abstract class MessageRecord extends DisplayRecord {
|
||||
return SmsDatabase.Types.isProcessedKeyExchange(type);
|
||||
}
|
||||
|
||||
public boolean isPendingFallbackApproval() {
|
||||
return SmsDatabase.Types.isPendingApprovalType(type);
|
||||
public boolean isPendingSmsFallback() {
|
||||
return SmsDatabase.Types.isPendingSmsFallbackType(type);
|
||||
}
|
||||
|
||||
public boolean isPendingSecureSmsFallback() {
|
||||
return SmsDatabase.Types.isPendingSecureSmsFallbackType(type);
|
||||
}
|
||||
|
||||
public boolean isPendingInsecureSmsFallback() {
|
||||
return SmsDatabase.Types.isPendingInsecureSmsFallbackType(type);
|
||||
}
|
||||
|
||||
public boolean isBundleKeyExchange() {
|
||||
|
@ -31,11 +31,12 @@ import org.thoughtcrime.securesms.notifications.MessageNotifier;
|
||||
import org.thoughtcrime.securesms.recipients.Recipients;
|
||||
import org.thoughtcrime.securesms.service.SendReceiveService.ToastHandler;
|
||||
import org.thoughtcrime.securesms.sms.IncomingIdentityUpdateMessage;
|
||||
import org.thoughtcrime.securesms.transport.InsecureFallbackApprovalException;
|
||||
import org.thoughtcrime.securesms.transport.RetryLaterException;
|
||||
import org.thoughtcrime.securesms.transport.SecureFallbackApprovalException;
|
||||
import org.thoughtcrime.securesms.transport.UndeliverableMessageException;
|
||||
import org.thoughtcrime.securesms.transport.UniversalTransport;
|
||||
import org.thoughtcrime.securesms.transport.UntrustedIdentityException;
|
||||
import org.thoughtcrime.securesms.transport.UserInterventionRequiredException;
|
||||
import org.whispersystems.textsecure.crypto.MasterSecret;
|
||||
|
||||
import ws.com.google.android.mms.MmsException;
|
||||
@ -84,16 +85,18 @@ public class MmsSender {
|
||||
result.getResponseStatus());
|
||||
|
||||
systemStateListener.unregisterForConnectivityChange();
|
||||
} catch (UserInterventionRequiredException uire) {
|
||||
Log.w("MmsSender", uire);
|
||||
database.markAsPendingApproval(message.getDatabaseMessageId());
|
||||
Recipients recipients = threads.getRecipientsForThreadId(threadId);
|
||||
MessageNotifier.notifyMessageDeliveryFailed(context, recipients, threadId);
|
||||
} catch (InsecureFallbackApprovalException ifae) {
|
||||
Log.w("MmsSender", ifae);
|
||||
database.markAsPendingInsecureSmsFallback(message.getDatabaseMessageId());
|
||||
notifyMessageDeliveryFailed(context, threads, threadId);
|
||||
} catch (SecureFallbackApprovalException sfae) {
|
||||
Log.w("MmsSender", sfae);
|
||||
database.markAsPendingSecureSmsFallback(message.getDatabaseMessageId());
|
||||
notifyMessageDeliveryFailed(context, threads, threadId);
|
||||
} catch (UndeliverableMessageException e) {
|
||||
Log.w("MmsSender", e);
|
||||
database.markAsSentFailed(message.getDatabaseMessageId());
|
||||
Recipients recipients = threads.getRecipientsForThreadId(threadId);
|
||||
MessageNotifier.notifyMessageDeliveryFailed(context, recipients, threadId);
|
||||
notifyMessageDeliveryFailed(context, threads, threadId);
|
||||
} catch (UntrustedIdentityException uie) {
|
||||
IncomingIdentityUpdateMessage identityUpdateMessage = IncomingIdentityUpdateMessage.createFor(message.getTo()[0].getString(), uie.getIdentityKey());
|
||||
DatabaseFactory.getEncryptingSmsDatabase(context).insertMessageInbox(masterSecret, identityUpdateMessage);
|
||||
@ -117,6 +120,11 @@ public class MmsSender {
|
||||
}
|
||||
}
|
||||
|
||||
private static void notifyMessageDeliveryFailed(Context context, ThreadDatabase threads, long threadId) {
|
||||
Recipients recipients = threads.getRecipientsForThreadId(threadId);
|
||||
MessageNotifier.notifyMessageDeliveryFailed(context, recipients, threadId);
|
||||
}
|
||||
|
||||
private void scheduleQuickRetryAlarm() {
|
||||
((AlarmManager)context.getSystemService(Context.ALARM_SERVICE))
|
||||
.set(AlarmManager.RTC_WAKEUP, System.currentTimeMillis() + (30 * 1000),
|
||||
|
@ -36,12 +36,12 @@ import org.thoughtcrime.securesms.notifications.MessageNotifier;
|
||||
import org.thoughtcrime.securesms.recipients.Recipients;
|
||||
import org.thoughtcrime.securesms.service.SendReceiveService.ToastHandler;
|
||||
import org.thoughtcrime.securesms.sms.IncomingIdentityUpdateMessage;
|
||||
import org.thoughtcrime.securesms.transport.InsecureFallbackApprovalException;
|
||||
import org.thoughtcrime.securesms.transport.RetryLaterException;
|
||||
import org.thoughtcrime.securesms.transport.SecureFallbackApprovalException;
|
||||
import org.thoughtcrime.securesms.transport.UndeliverableMessageException;
|
||||
import org.thoughtcrime.securesms.transport.UniversalTransport;
|
||||
import org.thoughtcrime.securesms.transport.UntrustedIdentityException;
|
||||
import org.thoughtcrime.securesms.transport.UserInterventionRequiredException;
|
||||
import org.thoughtcrime.securesms.util.TextSecurePreferences;
|
||||
import org.whispersystems.textsecure.crypto.MasterSecret;
|
||||
import org.whispersystems.textsecure.storage.Session;
|
||||
|
||||
@ -86,9 +86,13 @@ public class SmsSender {
|
||||
database.markAsSending(record.getId());
|
||||
|
||||
transport.deliver(record);
|
||||
} catch (UserInterventionRequiredException uire) {
|
||||
Log.w("SmsSender", uire);
|
||||
DatabaseFactory.getSmsDatabase(context).markAsPendingApproval(record.getId());
|
||||
} catch (InsecureFallbackApprovalException ifae) {
|
||||
Log.w("SmsSender", ifae);
|
||||
DatabaseFactory.getSmsDatabase(context).markAsPendingInsecureSmsFallback(record.getId());
|
||||
MessageNotifier.notifyMessageDeliveryFailed(context, record.getRecipients(), record.getThreadId());
|
||||
} catch (SecureFallbackApprovalException sfae) {
|
||||
Log.w("SmsSender", sfae);
|
||||
DatabaseFactory.getSmsDatabase(context).markAsPendingSecureSmsFallback(record.getId());
|
||||
MessageNotifier.notifyMessageDeliveryFailed(context, record.getRecipients(), record.getThreadId());
|
||||
} catch (UntrustedIdentityException e) {
|
||||
Log.w("SmsSender", e);
|
||||
|
@ -0,0 +1,7 @@
|
||||
package org.thoughtcrime.securesms.transport;
|
||||
|
||||
public class InsecureFallbackApprovalException extends Exception {
|
||||
public InsecureFallbackApprovalException(String detailMessage) {
|
||||
super(detailMessage);
|
||||
}
|
||||
}
|
@ -36,6 +36,7 @@ import org.whispersystems.textsecure.crypto.MasterSecret;
|
||||
import org.whispersystems.textsecure.crypto.SessionCipher;
|
||||
import org.whispersystems.textsecure.crypto.protocol.CiphertextMessage;
|
||||
import org.whispersystems.textsecure.storage.RecipientDevice;
|
||||
import org.whispersystems.textsecure.storage.Session;
|
||||
import org.whispersystems.textsecure.util.Hex;
|
||||
|
||||
import java.io.IOException;
|
||||
@ -62,7 +63,9 @@ public class MmsTransport {
|
||||
this.radio = MmsRadio.getInstance(context);
|
||||
}
|
||||
|
||||
public MmsSendResult deliver(SendReq message) throws UndeliverableMessageException {
|
||||
public MmsSendResult deliver(SendReq message) throws UndeliverableMessageException,
|
||||
InsecureFallbackApprovalException
|
||||
{
|
||||
if (TextSecurePreferences.isPushRegistered(context) &&
|
||||
!TextSecurePreferences.isSmsFallbackEnabled(context))
|
||||
{
|
||||
@ -109,7 +112,7 @@ public class MmsTransport {
|
||||
}
|
||||
|
||||
private MmsSendResult sendMms(SendReq message, boolean usingMmsRadio, boolean useProxy)
|
||||
throws IOException, UndeliverableMessageException
|
||||
throws IOException, UndeliverableMessageException, InsecureFallbackApprovalException
|
||||
{
|
||||
String number = ((TelephonyManager)context.getSystemService(Context.TELEPHONY_SERVICE)).getLine1Number();
|
||||
boolean upgradedSecure = false;
|
||||
@ -141,7 +144,7 @@ public class MmsTransport {
|
||||
}
|
||||
}
|
||||
|
||||
private SendReq getEncryptedMessage(SendReq pdu) {
|
||||
private SendReq getEncryptedMessage(SendReq pdu) throws InsecureFallbackApprovalException {
|
||||
EncodedStringValue[] encodedRecipient = pdu.getTo();
|
||||
String recipient = encodedRecipient[0].getString();
|
||||
byte[] pduBytes = new PduComposer(context, pdu).make();
|
||||
@ -162,11 +165,16 @@ public class MmsTransport {
|
||||
return encryptedPdu;
|
||||
}
|
||||
|
||||
private byte[] getEncryptedPdu(MasterSecret masterSecret, String recipientString, byte[] pduBytes) {
|
||||
private byte[] getEncryptedPdu(MasterSecret masterSecret, String recipientString, byte[] pduBytes) throws InsecureFallbackApprovalException {
|
||||
try {
|
||||
TextTransport transportDetails = new TextTransport();
|
||||
Recipient recipient = RecipientFactory.getRecipientsFromString(context, recipientString, false).getPrimaryRecipient();
|
||||
RecipientDevice recipientDevice = new RecipientDevice(recipient.getRecipientId(), RecipientDevice.DEFAULT_DEVICE_ID);
|
||||
|
||||
if (!Session.hasEncryptCapableSession(context, masterSecret, recipient, recipientDevice)) {
|
||||
throw new InsecureFallbackApprovalException("No session exists for this secure message.");
|
||||
}
|
||||
|
||||
SessionCipher sessionCipher = SessionCipher.createFor(context, masterSecret, recipientDevice);
|
||||
CiphertextMessage ciphertextMessage = sessionCipher.encrypt(pduBytes);
|
||||
|
||||
|
@ -0,0 +1,7 @@
|
||||
package org.thoughtcrime.securesms.transport;
|
||||
|
||||
public class SecureFallbackApprovalException extends Exception {
|
||||
public SecureFallbackApprovalException(String detailMessage) {
|
||||
super(detailMessage);
|
||||
}
|
||||
}
|
@ -33,6 +33,7 @@ import org.whispersystems.textsecure.crypto.MasterSecret;
|
||||
import org.whispersystems.textsecure.crypto.SessionCipher;
|
||||
import org.whispersystems.textsecure.crypto.protocol.CiphertextMessage;
|
||||
import org.whispersystems.textsecure.storage.RecipientDevice;
|
||||
import org.whispersystems.textsecure.storage.Session;
|
||||
|
||||
import java.util.ArrayList;
|
||||
|
||||
@ -46,7 +47,9 @@ public class SmsTransport extends BaseTransport {
|
||||
this.masterSecret = masterSecret;
|
||||
}
|
||||
|
||||
public void deliver(SmsMessageRecord message) throws UndeliverableMessageException {
|
||||
public void deliver(SmsMessageRecord message) throws UndeliverableMessageException,
|
||||
InsecureFallbackApprovalException
|
||||
{
|
||||
if (!TextSecurePreferences.isSmsNonDataOutEnabled(context) && !TextSecurePreferences.isSmsFallbackEnabled(context)) {
|
||||
throw new UndeliverableMessageException("SMS Transport is not enabled!");
|
||||
}
|
||||
@ -58,7 +61,9 @@ public class SmsTransport extends BaseTransport {
|
||||
}
|
||||
}
|
||||
|
||||
private void deliverSecureMessage(SmsMessageRecord message) throws UndeliverableMessageException {
|
||||
private void deliverSecureMessage(SmsMessageRecord message) throws UndeliverableMessageException,
|
||||
InsecureFallbackApprovalException
|
||||
{
|
||||
MultipartSmsMessageHandler multipartMessageHandler = new MultipartSmsMessageHandler();
|
||||
OutgoingTextMessage transportMessage = OutgoingTextMessage.from(message);
|
||||
|
||||
@ -161,9 +166,16 @@ public class SmsTransport extends BaseTransport {
|
||||
|
||||
private OutgoingTextMessage getAsymmetricEncrypt(MasterSecret masterSecret,
|
||||
OutgoingTextMessage message)
|
||||
throws InsecureFallbackApprovalException
|
||||
{
|
||||
Recipient recipient = message.getRecipients().getPrimaryRecipient();
|
||||
RecipientDevice recipientDevice = new RecipientDevice(recipient.getRecipientId(), RecipientDevice.DEFAULT_DEVICE_ID);
|
||||
RecipientDevice recipientDevice = new RecipientDevice(recipient.getRecipientId(),
|
||||
RecipientDevice.DEFAULT_DEVICE_ID);
|
||||
|
||||
if (!Session.hasEncryptCapableSession(context, masterSecret, recipient, recipientDevice)) {
|
||||
throw new InsecureFallbackApprovalException("No session exists for this secure message.");
|
||||
}
|
||||
|
||||
String body = message.getMessageBody();
|
||||
SmsTransportDetails transportDetails = new SmsTransportDetails();
|
||||
SessionCipher sessionCipher = SessionCipher.createFor(context, masterSecret, recipientDevice);
|
||||
|
@ -24,6 +24,7 @@ import org.thoughtcrime.securesms.database.model.SmsMessageRecord;
|
||||
import org.thoughtcrime.securesms.mms.MmsSendResult;
|
||||
import org.thoughtcrime.securesms.push.PushServiceSocketFactory;
|
||||
import org.thoughtcrime.securesms.recipients.Recipient;
|
||||
import org.thoughtcrime.securesms.recipients.RecipientFactory;
|
||||
import org.thoughtcrime.securesms.recipients.RecipientFormattingException;
|
||||
import org.thoughtcrime.securesms.sms.IncomingGroupMessage;
|
||||
import org.thoughtcrime.securesms.sms.IncomingIdentityUpdateMessage;
|
||||
@ -36,6 +37,7 @@ import org.whispersystems.textsecure.directory.NotInDirectoryException;
|
||||
import org.whispersystems.textsecure.push.ContactTokenDetails;
|
||||
import org.whispersystems.textsecure.push.PushServiceSocket;
|
||||
import org.whispersystems.textsecure.push.UnregisteredUserException;
|
||||
import org.whispersystems.textsecure.storage.Session;
|
||||
import org.whispersystems.textsecure.util.DirectoryUtil;
|
||||
import org.whispersystems.textsecure.util.InvalidNumberException;
|
||||
|
||||
@ -60,7 +62,8 @@ public class UniversalTransport {
|
||||
}
|
||||
|
||||
public void deliver(SmsMessageRecord message)
|
||||
throws UndeliverableMessageException, UntrustedIdentityException, RetryLaterException, UserInterventionRequiredException
|
||||
throws UndeliverableMessageException, UntrustedIdentityException, RetryLaterException,
|
||||
SecureFallbackApprovalException, InsecureFallbackApprovalException
|
||||
{
|
||||
if (!TextSecurePreferences.isPushRegistered(context)) {
|
||||
smsTransport.deliver(message);
|
||||
@ -99,7 +102,8 @@ public class UniversalTransport {
|
||||
}
|
||||
|
||||
public MmsSendResult deliver(SendReq mediaMessage, long threadId)
|
||||
throws UndeliverableMessageException, RetryLaterException, UntrustedIdentityException, UserInterventionRequiredException
|
||||
throws UndeliverableMessageException, RetryLaterException, UntrustedIdentityException,
|
||||
SecureFallbackApprovalException, InsecureFallbackApprovalException
|
||||
{
|
||||
if (Util.isEmpty(mediaMessage.getTo())) {
|
||||
return mmsTransport.deliver(mediaMessage);
|
||||
@ -155,28 +159,42 @@ public class UniversalTransport {
|
||||
}
|
||||
|
||||
private MmsSendResult fallbackOrAskApproval(SendReq mediaMessage, String destination)
|
||||
throws UserInterventionRequiredException, UndeliverableMessageException
|
||||
throws SecureFallbackApprovalException, UndeliverableMessageException, InsecureFallbackApprovalException
|
||||
{
|
||||
boolean isSmsFallbackApprovalRequired = isSmsFallbackApprovalRequired(destination);
|
||||
if (!isSmsFallbackApprovalRequired) {
|
||||
Log.i("UniversalTransport", "Falling back to MMS without user intervention");
|
||||
return mmsTransport.deliver(mediaMessage);
|
||||
} else {
|
||||
Log.i("UniversalTransport", "Marking message as pending user approval per their settings");
|
||||
throw new UserInterventionRequiredException("Pending user approval for fallback to SMS");
|
||||
try {
|
||||
Recipient recipient = RecipientFactory.getRecipientsFromString(context, destination, false).getPrimaryRecipient();
|
||||
boolean isSmsFallbackApprovalRequired = isSmsFallbackApprovalRequired(destination);
|
||||
|
||||
if (!isSmsFallbackApprovalRequired) {
|
||||
Log.w("UniversalTransport", "Falling back to MMS");
|
||||
return mmsTransport.deliver(mediaMessage);
|
||||
} else if (!Session.hasEncryptCapableSession(context, masterSecret, recipient)) {
|
||||
Log.w("UniversalTransport", "Marking message as pending insecure SMS fallback");
|
||||
throw new InsecureFallbackApprovalException("Pending user approval for fallback to insecure SMS");
|
||||
} else {
|
||||
Log.w("UniversalTransport", "Marking message as pending secure SMS fallback");
|
||||
throw new SecureFallbackApprovalException("Pending user approval for fallback secure to SMS");
|
||||
}
|
||||
} catch (RecipientFormattingException rfe) {
|
||||
throw new UndeliverableMessageException(rfe);
|
||||
}
|
||||
}
|
||||
|
||||
private void fallbackOrAskApproval(SmsMessageRecord smsMessage, String destination)
|
||||
throws UserInterventionRequiredException, UndeliverableMessageException
|
||||
throws SecureFallbackApprovalException, UndeliverableMessageException, InsecureFallbackApprovalException
|
||||
{
|
||||
boolean isSmsFallbackApprovalRequired = isSmsFallbackApprovalRequired(destination);
|
||||
Recipient recipient = smsMessage.getIndividualRecipient();
|
||||
boolean isSmsFallbackApprovalRequired = isSmsFallbackApprovalRequired(destination);
|
||||
|
||||
if (!isSmsFallbackApprovalRequired) {
|
||||
Log.i("UniversalTransport", "Falling back to SMS without user intervention");
|
||||
Log.w("UniversalTransport", "Falling back to SMS");
|
||||
smsTransport.deliver(smsMessage);
|
||||
} else if (!Session.hasEncryptCapableSession(context, masterSecret, recipient)) {
|
||||
Log.w("UniversalTransport", "Marking message as pending insecure fallback.");
|
||||
throw new InsecureFallbackApprovalException("Pending user approval for fallback to insecure SMS");
|
||||
} else {
|
||||
Log.i("UniversalTransport", "Marking message as pending user approval per their settings");
|
||||
throw new UserInterventionRequiredException("Pending user approval for fallback to SMS");
|
||||
Log.w("UniversalTransport", "Marking message as pending secure fallback.");
|
||||
throw new SecureFallbackApprovalException("Pending user approval for fallback to secure SMS");
|
||||
}
|
||||
}
|
||||
|
||||
@ -218,7 +236,6 @@ public class UniversalTransport {
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
public boolean isMultipleRecipients(SendReq mediaMessage) {
|
||||
int recipientCount = 0;
|
||||
|
||||
@ -267,9 +284,9 @@ public class UniversalTransport {
|
||||
return directory.isActiveNumber(destination);
|
||||
} catch (NotInDirectoryException e) {
|
||||
try {
|
||||
PushServiceSocket socket = PushServiceSocketFactory.create(context);
|
||||
String contactToken = DirectoryUtil.getDirectoryServerToken(destination);
|
||||
ContactTokenDetails registeredUser = socket.getContactTokenDetails(contactToken);
|
||||
PushServiceSocket socket = PushServiceSocketFactory.create(context);
|
||||
String contactToken = DirectoryUtil.getDirectoryServerToken(destination);
|
||||
ContactTokenDetails registeredUser = socket.getContactTokenDetails(contactToken);
|
||||
|
||||
if (registeredUser == null) {
|
||||
registeredUser = new ContactTokenDetails();
|
||||
|
@ -1,7 +0,0 @@
|
||||
package org.thoughtcrime.securesms.transport;
|
||||
|
||||
public class UserInterventionRequiredException extends Exception {
|
||||
public UserInterventionRequiredException(String detailMessage) {
|
||||
super(detailMessage);
|
||||
}
|
||||
}
|
Loading…
x
Reference in New Issue
Block a user