mirror of
https://github.com/oxen-io/session-android.git
synced 2025-10-25 12:48:33 +00:00
UX for unencrypted fallback case
This commit is contained in:
committed by
Moxie Marlinspike
parent
40629a3bcf
commit
832763f695
@@ -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);
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user