Make UI responsive to UniversalTransport upgrades.

This commit is contained in:
Moxie Marlinspike 2013-11-18 13:16:18 -08:00
parent 07b7696937
commit dadabdfaa8
9 changed files with 50 additions and 26 deletions

View File

@ -146,7 +146,7 @@ public class KeyExchangeProcessor {
.saveIdentity(masterSecret, recipient, remoteIdentity);
}
public void processKeyExchangeMessage(PreKeyEntity message) {
public void processKeyExchangeMessage(PreKeyEntity message, long threadId) {
PublicKey remoteKey = new PublicKey(message.getKeyId(), message.getPublicKey());
remoteKeyRecord.setCurrentRemoteKey(remoteKey);
remoteKeyRecord.setLastRemoteKey(remoteKey);
@ -166,6 +166,8 @@ public class KeyExchangeProcessor {
DatabaseFactory.getIdentityDatabase(context)
.saveIdentity(masterSecret, recipient, message.getIdentityKey());
broadcastSecurityUpdateEvent(context, threadId);
}
public void processKeyExchangeMessage(KeyExchangeMessage message, long threadId) {
@ -202,6 +204,10 @@ public class KeyExchangeProcessor {
DecryptingQueue.scheduleRogueMessages(context, masterSecret, recipient);
broadcastSecurityUpdateEvent(context, threadId);
}
private static void broadcastSecurityUpdateEvent(Context context, long threadId) {
Intent intent = new Intent(SECURITY_UPDATE_EVENT);
intent.putExtra("thread_id", threadId);
intent.setPackage(context.getPackageName());

View File

@ -166,6 +166,10 @@ public class SmsDatabase extends Database implements MmsSmsColumns {
updateTypeBitmask(id, 0, Types.KEY_EXCHANGE_CORRUPTED_BIT);
}
public void markAsSecure(long id) {
updateTypeBitmask(id, 0, Types.SECURE_MESSAGE_BIT);
}
public void markAsDecryptFailed(long id) {
updateTypeBitmask(id, Types.ENCRYPTION_MASK, Types.ENCRYPTION_REMOTE_FAILED_BIT);
}

View File

@ -21,7 +21,6 @@ import android.content.Intent;
import android.util.Log;
import android.util.Pair;
import org.whispersystems.textsecure.crypto.MasterSecret;
import org.thoughtcrime.securesms.database.DatabaseFactory;
import org.thoughtcrime.securesms.database.MmsDatabase;
import org.thoughtcrime.securesms.database.ThreadDatabase;
@ -30,6 +29,7 @@ import org.thoughtcrime.securesms.recipients.Recipients;
import org.thoughtcrime.securesms.service.SendReceiveService.ToastHandler;
import org.thoughtcrime.securesms.transport.UndeliverableMessageException;
import org.thoughtcrime.securesms.transport.UniversalTransport;
import org.whispersystems.textsecure.crypto.MasterSecret;
import ws.com.google.android.mms.MmsException;
import ws.com.google.android.mms.pdu.SendReq;
@ -37,16 +37,14 @@ import ws.com.google.android.mms.pdu.SendReq;
public class MmsSender {
private final Context context;
private final ToastHandler toastHandler;
public MmsSender(Context context, ToastHandler toastHandler) {
this.context = context;
this.toastHandler = toastHandler;
}
public void process(MasterSecret masterSecret, Intent intent) {
Log.w("MmsSender", "Got intent action: " + intent.getAction());
if (intent.getAction().equals(SendReceiveService.SEND_MMS_ACTION)) {
if (SendReceiveService.SEND_MMS_ACTION.equals(intent.getAction())) {
handleSendMms(masterSecret, intent);
}
}
@ -61,15 +59,16 @@ public class MmsSender {
SendReq[] messages = database.getOutgoingMessages(masterSecret, messageId);
for (SendReq message : messages) {
long threadId = database.getThreadIdForMessage(message.getDatabaseMessageId());
try {
Log.w("MmsSender", "Passing to MMS transport: " + message.getDatabaseMessageId());
database.markAsSending(message.getDatabaseMessageId());
Pair<byte[], Integer> result = transport.deliver(message);
Pair<byte[], Integer> result = transport.deliver(message, threadId);
database.markAsSent(message.getDatabaseMessageId(), result.first, result.second);
} catch (UndeliverableMessageException e) {
Log.w("MmsSender", e);
database.markAsSentFailed(message.getDatabaseMessageId());
long threadId = database.getThreadIdForMessage(messageId);
Recipients recipients = threads.getRecipientsForThreadId(threadId);
MessageNotifier.notifyMessageDeliveryFailed(context, recipients, threadId);
}

View File

@ -85,12 +85,18 @@ public class SmsSender {
private void handleSentMessage(Intent intent) {
long messageId = intent.getLongExtra("message_id", -1);
int result = intent.getIntExtra("ResultCode", -31337);
boolean upgraded = intent.getBooleanExtra("upgraded", false);
Log.w("SMSReceiverService", "Intent resultcode: " + result);
Log.w("SMSReceiverService", "Running sent callback: " + messageId);
if (result == Activity.RESULT_OK) {
DatabaseFactory.getSmsDatabase(context).markAsSent(messageId);
if (upgraded) {
DatabaseFactory.getSmsDatabase(context).markAsSecure(messageId);
}
unregisterForRadioChanges();
} else if (result == SmsManager.RESULT_ERROR_NO_SERVICE || result == SmsManager.RESULT_ERROR_RADIO_OFF) {
DatabaseFactory.getSmsDatabase(context).markAsOutbox(messageId);

View File

@ -133,6 +133,7 @@ public class MessageSender {
Intent intent = new Intent(SendReceiveService.SEND_MMS_ACTION, null,
context, SendReceiveService.class);
intent.putExtra("message_id", messageId);
intent.putExtra("thread_id", threadId);
context.startService(intent);
}

View File

@ -9,13 +9,14 @@ import org.thoughtcrime.securesms.service.SmsListener;
public abstract class BaseTransport {
protected Intent constructSentIntent(Context context, long messageId, long type) {
protected Intent constructSentIntent(Context context, long messageId, long type, boolean upgraded) {
Intent pending = new Intent(SendReceiveService.SENT_SMS_ACTION,
Uri.parse("custom://" + messageId + System.currentTimeMillis()),
context, SmsListener.class);
pending.putExtra("type", type);
pending.putExtra("message_id", messageId);
pending.putExtra("upgraded", upgraded);
return pending;
}

View File

@ -73,24 +73,27 @@ public class PushTransport extends BaseTransport {
try {
TextSecurePushCredentials credentials = TextSecurePushCredentials.getInstance();
Recipient recipient = message.getIndividualRecipient();
long threadId = message.getThreadId();
PushServiceSocket socket = new PushServiceSocket(context, credentials);
PushDestination destination = PushDestination.create(context, credentials,
recipient.getNumber());
String plaintextBody = message.getBody().getBody();
byte[] plaintext = PushMessageContent.newBuilder().setBody(plaintextBody).build().toByteArray();
PushBody pushBody = getEncryptedMessage(socket, recipient, destination, plaintext);
PushBody pushBody = getEncryptedMessage(socket, threadId, recipient, destination, plaintext);
socket.sendMessage(destination, pushBody);
context.sendBroadcast(constructSentIntent(context, message.getId(), message.getType()));
context.sendBroadcast(constructSentIntent(context, message.getId(), message.getType(), true));
} catch (RateLimitException e) {
Log.w("PushTransport", e);
throw new IOException("Rate limit exceeded.");
}
}
public void deliver(SendReq message, List<PushDestination> destinations) throws IOException {
public void deliver(SendReq message, List<PushDestination> destinations, long threadId)
throws IOException
{
try {
TextSecurePushCredentials credentials = TextSecurePushCredentials.getInstance();
PushServiceSocket socket = new PushServiceSocket(context, credentials);
@ -118,7 +121,7 @@ public class PushTransport extends BaseTransport {
}
byte[] plaintext = builder.build().toByteArray();
PushBody pushBody = getEncryptedMessage(socket, recipients.getPrimaryRecipient(), destination, plaintext);
PushBody pushBody = getEncryptedMessage(socket, threadId, recipients.getPrimaryRecipient(), destination, plaintext);
pushBodies.add(pushBody);
}
@ -158,7 +161,7 @@ public class PushTransport extends BaseTransport {
return attachments;
}
private PushBody getEncryptedMessage(PushServiceSocket socket, Recipient recipient,
private PushBody getEncryptedMessage(PushServiceSocket socket, long threadId, Recipient recipient,
PushDestination pushDestination, byte[] plaintext)
throws IOException
{
@ -172,7 +175,7 @@ public class PushTransport extends BaseTransport {
return new PushBody(OutgoingPushMessage.TYPE_MESSAGE_PREKEY_BUNDLE, ciphertext);
} else {
Log.w("PushTransport", "Sending prekeybundle ciphertext message for new session...");
byte[] ciphertext = getEncryptedPrekeyBundleMessageForNewSession(socket, recipient, pushDestination, plaintext);
byte[] ciphertext = getEncryptedPrekeyBundleMessageForNewSession(socket, threadId, recipient, pushDestination, plaintext);
return new PushBody(OutgoingPushMessage.TYPE_MESSAGE_PREKEY_BUNDLE, ciphertext);
}
}
@ -190,6 +193,7 @@ public class PushTransport extends BaseTransport {
}
private byte[] getEncryptedPrekeyBundleMessageForNewSession(PushServiceSocket socket,
long threadId,
Recipient recipient,
PushDestination pushDestination,
byte[] plaintext)
@ -200,7 +204,7 @@ public class PushTransport extends BaseTransport {
PreKeyEntity preKey = socket.getPreKey(pushDestination);
KeyExchangeProcessor processor = new KeyExchangeProcessor(context, masterSecret, recipient);
processor.processKeyExchangeMessage(preKey);
processor.processKeyExchangeMessage(preKey, threadId);
MessageCipher messageCipher = new MessageCipher(context, masterSecret, identityKeyPair);
CiphertextMessage ciphertextMessage = messageCipher.encrypt(recipient, plaintext);

View File

@ -37,7 +37,6 @@ import org.whispersystems.textsecure.crypto.KeyUtil;
import org.whispersystems.textsecure.crypto.MasterSecret;
import org.whispersystems.textsecure.crypto.MessageCipher;
import org.whispersystems.textsecure.crypto.ecc.Curve;
import org.whispersystems.textsecure.crypto.ecc.ECPublicKey;
import org.whispersystems.textsecure.crypto.protocol.CiphertextMessage;
import org.whispersystems.textsecure.crypto.protocol.PreKeyBundleMessage;
@ -70,7 +69,7 @@ public class SmsTransport extends BaseTransport {
}
ArrayList<String> messages = multipartMessageHandler.divideMessage(transportMessage);
ArrayList<PendingIntent> sentIntents = constructSentIntents(message.getId(), message.getType(), messages);
ArrayList<PendingIntent> sentIntents = constructSentIntents(message.getId(), message.getType(), messages, true);
ArrayList<PendingIntent> deliveredIntents = constructDeliveredIntents(message.getId(), message.getType(), messages);
Log.w("SmsTransport", "Secure divide into message parts: " + messages.size());
@ -103,7 +102,7 @@ public class SmsTransport extends BaseTransport {
throws UndeliverableMessageException
{
ArrayList<String> messages = SmsManager.getDefault().divideMessage(message.getBody().getBody());
ArrayList<PendingIntent> sentIntents = constructSentIntents(message.getId(), message.getType(), messages);
ArrayList<PendingIntent> sentIntents = constructSentIntents(message.getId(), message.getType(), messages, false);
ArrayList<PendingIntent> deliveredIntents = constructDeliveredIntents(message.getId(), message.getType(), messages);
String recipient = message.getIndividualRecipient().getNumber();
@ -132,12 +131,14 @@ public class SmsTransport extends BaseTransport {
}
}
private ArrayList<PendingIntent> constructSentIntents(long messageId, long type, ArrayList<String> messages) {
private ArrayList<PendingIntent> constructSentIntents(long messageId, long type,
ArrayList<String> messages, boolean secure)
{
ArrayList<PendingIntent> sentIntents = new ArrayList<PendingIntent>(messages.size());
for (String ignored : messages) {
sentIntents.add(PendingIntent.getBroadcast(context, 0,
constructSentIntent(context, messageId, type),
constructSentIntent(context, messageId, type, secure),
0));
}

View File

@ -76,7 +76,9 @@ public class UniversalTransport {
}
}
public Pair<byte[], Integer> deliver(SendReq mediaMessage) throws UndeliverableMessageException {
public Pair<byte[], Integer> deliver(SendReq mediaMessage, long threadId)
throws UndeliverableMessageException
{
if (!TextSecurePreferences.isPushRegistered(context)) {
return mmsTransport.deliver(mediaMessage);
}
@ -86,7 +88,7 @@ public class UniversalTransport {
if (isPushTransport(destinations)) {
try {
Log.w("UniversalTransport", "Delivering media message with GCM...");
pushTransport.deliver(mediaMessage, destinations);
pushTransport.deliver(mediaMessage, destinations, threadId);
return new Pair<byte[], Integer>("push".getBytes("UTF-8"), 0);
} catch (IOException ioe) {
Log.w("UniversalTransport", ioe);