diff --git a/res/values/strings.xml b/res/values/strings.xml
index f32a571bc9..f1626a8f90 100644
--- a/res/values/strings.xml
+++ b/res/values/strings.xml
@@ -264,6 +264,7 @@
Received message with unknown identity key. Click to process and display.
+ Received updated but unknown identity information. Tap to validate identity.
diff --git a/src/org/thoughtcrime/securesms/ConversationItem.java b/src/org/thoughtcrime/securesms/ConversationItem.java
index 897efa6448..26b92ad700 100644
--- a/src/org/thoughtcrime/securesms/ConversationItem.java
+++ b/src/org/thoughtcrime/securesms/ConversationItem.java
@@ -358,6 +358,7 @@ public class ConversationItem extends LinearLayout {
intent.putExtra("thread_id", messageRecord.getThreadId());
intent.putExtra("message_id", messageRecord.getId());
intent.putExtra("is_bundle", messageRecord.isBundleKeyExchange());
+ intent.putExtra("is_identity_update", messageRecord.isIdentityUpdate());
intent.putExtra("master_secret", masterSecret);
intent.putExtra("sent", messageRecord.isOutgoing());
context.startActivity(intent);
diff --git a/src/org/thoughtcrime/securesms/ReceiveKeyActivity.java b/src/org/thoughtcrime/securesms/ReceiveKeyActivity.java
index 0d236cf89e..90bfbb39bd 100644
--- a/src/org/thoughtcrime/securesms/ReceiveKeyActivity.java
+++ b/src/org/thoughtcrime/securesms/ReceiveKeyActivity.java
@@ -47,6 +47,7 @@ import org.whispersystems.textsecure.crypto.protocol.CiphertextMessage;
import org.whispersystems.textsecure.crypto.protocol.PreKeyWhisperMessage;
import org.whispersystems.textsecure.storage.InvalidKeyIdException;
import org.whispersystems.textsecure.storage.RecipientDevice;
+import org.whispersystems.textsecure.util.Base64;
import java.io.IOException;
@@ -71,6 +72,7 @@ public class ReceiveKeyActivity extends Activity {
private MasterSecret masterSecret;
private PreKeyWhisperMessage keyExchangeMessageBundle;
private KeyExchangeMessage keyExchangeMessage;
+ private IdentityKey identityUpdateMessage;
@Override
protected void onCreate(Bundle state) {
@@ -99,8 +101,11 @@ public class ReceiveKeyActivity extends Activity {
}
private void initializeText() {
- if (isTrusted(keyExchangeMessage, keyExchangeMessageBundle)) initializeTrustedText();
- else initializeUntrustedText();
+ if (isTrusted(keyExchangeMessage, keyExchangeMessageBundle, identityUpdateMessage)) {
+ initializeTrustedText();
+ } else {
+ initializeUntrustedText();
+ }
}
private void initializeTrustedText() {
@@ -113,12 +118,16 @@ public class ReceiveKeyActivity extends Activity {
spannableString.setSpan(new ClickableSpan() {
@Override
public void onClick(View widget) {
+ IdentityKey remoteIdentity;
+
+ if (identityUpdateMessage != null) remoteIdentity = identityUpdateMessage;
+ else if (keyExchangeMessageBundle != null) remoteIdentity = keyExchangeMessageBundle.getIdentityKey();
+ else remoteIdentity = keyExchangeMessage.getIdentityKey();
+
Intent intent = new Intent(ReceiveKeyActivity.this, VerifyIdentityActivity.class);
intent.putExtra("recipient", recipient);
intent.putExtra("master_secret", masterSecret);
- intent.putExtra("remote_identity",
- keyExchangeMessage == null ?
- keyExchangeMessageBundle.getIdentityKey() : keyExchangeMessage.getIdentityKey());
+ intent.putExtra("remote_identity", remoteIdentity);
startActivity(intent);
}
}, getString(R.string.ReceiveKeyActivity_the_signature_on_this_key_exchange_is_different).length() +1,
@@ -128,7 +137,7 @@ public class ReceiveKeyActivity extends Activity {
descriptionText.setMovementMethod(LinkMovementMethod.getInstance());
}
- private boolean isTrusted(KeyExchangeMessage message, PreKeyWhisperMessage messageBundle) {
+ private boolean isTrusted(KeyExchangeMessage message, PreKeyWhisperMessage messageBundle, IdentityKey identityUpdateMessage) {
RecipientDevice recipientDevice = new RecipientDevice(recipient.getRecipientId(), recipientDeviceId);
if (message != null) {
@@ -138,6 +147,9 @@ public class ReceiveKeyActivity extends Activity {
} else if (messageBundle != null) {
KeyExchangeProcessorV2 processor = new KeyExchangeProcessorV2(this, masterSecret, recipientDevice);
return processor.isTrusted(messageBundle);
+ } else if (identityUpdateMessage != null) {
+ KeyExchangeProcessorV2 processor = new KeyExchangeProcessorV2(this, masterSecret, recipientDevice);
+ return processor.isTrusted(identityUpdateMessage);
}
return false;
@@ -154,6 +166,8 @@ public class ReceiveKeyActivity extends Activity {
byte[] body = transportDetails.getDecodedMessage(messageBody.getBytes());
this.keyExchangeMessageBundle = new PreKeyWhisperMessage(body);
+ } else if (getIntent().getBooleanExtra("is_identity_update", false)) {
+ this.identityUpdateMessage = new IdentityKey(Base64.decodeWithoutPadding(messageBody), 0);
} else {
this.keyExchangeMessage = KeyExchangeMessage.createFor(messageBody);
}
@@ -232,6 +246,11 @@ public class ReceiveKeyActivity extends Activity {
DatabaseFactory.getEncryptingSmsDatabase(ReceiveKeyActivity.this)
.markAsCorruptKeyExchange(messageId);
}
+ } else if (identityUpdateMessage != null) {
+ DatabaseFactory.getIdentityDatabase(ReceiveKeyActivity.this)
+ .saveIdentity(masterSecret, recipient.getRecipientId(), identityUpdateMessage);
+
+ DatabaseFactory.getSmsDatabase(ReceiveKeyActivity.this).markAsProcessedKeyExchange(messageId);
}
diff --git a/src/org/thoughtcrime/securesms/crypto/KeyExchangeProcessorV2.java b/src/org/thoughtcrime/securesms/crypto/KeyExchangeProcessorV2.java
index 77849922f7..bf7f1a08df 100644
--- a/src/org/thoughtcrime/securesms/crypto/KeyExchangeProcessorV2.java
+++ b/src/org/thoughtcrime/securesms/crypto/KeyExchangeProcessorV2.java
@@ -55,6 +55,10 @@ public class KeyExchangeProcessorV2 extends KeyExchangeProcessor {
return isTrusted(message.getIdentityKey());
}
+ public boolean isTrusted(PreKeyEntity entity) {
+ return isTrusted(entity.getIdentityKey());
+ }
+
public boolean isTrusted(KeyExchangeMessage message) {
return message.hasIdentityKey() && isTrusted(message.getIdentityKey());
}
diff --git a/src/org/thoughtcrime/securesms/database/MmsSmsColumns.java b/src/org/thoughtcrime/securesms/database/MmsSmsColumns.java
index d8955ec617..8bf5d83a4d 100644
--- a/src/org/thoughtcrime/securesms/database/MmsSmsColumns.java
+++ b/src/org/thoughtcrime/securesms/database/MmsSmsColumns.java
@@ -35,6 +35,7 @@ public interface MmsSmsColumns {
protected static final long KEY_EXCHANGE_CORRUPTED_BIT = 0x1000;
protected static final long KEY_EXCHANGE_INVALID_VERSION_BIT = 0x800;
protected static final long KEY_EXCHANGE_BUNDLE_BIT = 0x400;
+ protected static final long KEY_EXCHANGE_IDENTITY_UPDATE_BIT = 0x200;
// Secure Message Information
protected static final long SECURE_MESSAGE_BIT = 0x800000;
@@ -98,6 +99,10 @@ public interface MmsSmsColumns {
return (type & KEY_EXCHANGE_BUNDLE_BIT) != 0;
}
+ public static boolean isIdentityUpdate(long type) {
+ return (type & KEY_EXCHANGE_IDENTITY_UPDATE_BIT) != 0;
+ }
+
public static boolean isSymmetricEncryption(long type) {
return (type & ENCRYPTION_SYMMETRIC_BIT) != 0;
}
diff --git a/src/org/thoughtcrime/securesms/database/SmsDatabase.java b/src/org/thoughtcrime/securesms/database/SmsDatabase.java
index 57bf11e593..481a631b64 100644
--- a/src/org/thoughtcrime/securesms/database/SmsDatabase.java
+++ b/src/org/thoughtcrime/securesms/database/SmsDatabase.java
@@ -252,6 +252,7 @@ public class SmsDatabase extends Database implements MmsSmsColumns {
else if (((IncomingKeyExchangeMessage)message).isCorrupted()) type |= Types.KEY_EXCHANGE_CORRUPTED_BIT;
else if (((IncomingKeyExchangeMessage)message).isInvalidVersion()) type |= Types.KEY_EXCHANGE_INVALID_VERSION_BIT;
else if (((IncomingKeyExchangeMessage)message).isPreKeyBundle()) type |= Types.KEY_EXCHANGE_BUNDLE_BIT;
+ else if (((IncomingKeyExchangeMessage)message).isIdentityUpdate()) type |= Types.KEY_EXCHANGE_IDENTITY_UPDATE_BIT;
} else if (message.isSecureMessage()) {
type |= Types.SECURE_MESSAGE_BIT;
type |= Types.ENCRYPTION_REMOTE_BIT;
diff --git a/src/org/thoughtcrime/securesms/database/model/MessageRecord.java b/src/org/thoughtcrime/securesms/database/model/MessageRecord.java
index 98b57e9a5f..7bf7285b13 100644
--- a/src/org/thoughtcrime/securesms/database/model/MessageRecord.java
+++ b/src/org/thoughtcrime/securesms/database/model/MessageRecord.java
@@ -111,6 +111,10 @@ public abstract class MessageRecord extends DisplayRecord {
return SmsDatabase.Types.isBundleKeyExchange(type);
}
+ public boolean isIdentityUpdate() {
+ return SmsDatabase.Types.isIdentityUpdate(type);
+ }
+
public boolean isCorruptedKeyExchange() {
return SmsDatabase.Types.isCorruptedKeyExchange(type);
}
diff --git a/src/org/thoughtcrime/securesms/database/model/SmsMessageRecord.java b/src/org/thoughtcrime/securesms/database/model/SmsMessageRecord.java
index 3b7e35798d..83357bfc2f 100644
--- a/src/org/thoughtcrime/securesms/database/model/SmsMessageRecord.java
+++ b/src/org/thoughtcrime/securesms/database/model/SmsMessageRecord.java
@@ -65,6 +65,8 @@ public class SmsMessageRecord extends MessageRecord {
return emphasisAdded(context.getString(R.string.SmsMessageRecord_received_key_exchange_message_for_invalid_protocol_version));
} else if (isBundleKeyExchange()) {
return emphasisAdded(context.getString(R.string.SmsMessageRecord_received_message_with_unknown_identity_key_click_to_process));
+ } else if (isIdentityUpdate()) {
+ return emphasisAdded(context.getString(R.string.SmsMessageRecord_received_updated_but_unknown_identity_information));
} else if (isKeyExchange() && isOutgoing()) {
return new SpannableString("");
} else if (isKeyExchange() && !isOutgoing()) {
diff --git a/src/org/thoughtcrime/securesms/service/MmsSender.java b/src/org/thoughtcrime/securesms/service/MmsSender.java
index 8ecd3515eb..58ff6a1c02 100644
--- a/src/org/thoughtcrime/securesms/service/MmsSender.java
+++ b/src/org/thoughtcrime/securesms/service/MmsSender.java
@@ -30,10 +30,14 @@ import org.thoughtcrime.securesms.mms.MmsSendResult;
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.sms.IncomingTextMessage;
import org.thoughtcrime.securesms.transport.RetryLaterException;
import org.thoughtcrime.securesms.transport.UndeliverableMessageException;
import org.thoughtcrime.securesms.transport.UniversalTransport;
+import org.thoughtcrime.securesms.transport.UntrustedIdentityException;
import org.whispersystems.textsecure.crypto.MasterSecret;
+import org.whispersystems.textsecure.util.Base64;
import ws.com.google.android.mms.MmsException;
import ws.com.google.android.mms.pdu.SendReq;
@@ -87,6 +91,11 @@ public class MmsSender {
database.markAsSentFailed(message.getDatabaseMessageId());
Recipients recipients = threads.getRecipientsForThreadId(threadId);
MessageNotifier.notifyMessageDeliveryFailed(context, recipients, threadId);
+ } catch (UntrustedIdentityException uie) {
+ IncomingTextMessage base = new IncomingTextMessage(message);
+ IncomingIdentityUpdateMessage identityUpdateMessage = new IncomingIdentityUpdateMessage(base, Base64.encodeBytesWithoutPadding(uie.getIdentityKey().serialize()));
+ DatabaseFactory.getEncryptingSmsDatabase(context).insertMessageInbox(masterSecret, identityUpdateMessage);
+ database.markAsSentFailed(messageId);
} catch (RetryLaterException e) {
Log.w("MmsSender", e);
database.markAsOutbox(message.getDatabaseMessageId());
diff --git a/src/org/thoughtcrime/securesms/service/SmsSender.java b/src/org/thoughtcrime/securesms/service/SmsSender.java
index dcc8752712..a08cde0a3c 100644
--- a/src/org/thoughtcrime/securesms/service/SmsSender.java
+++ b/src/org/thoughtcrime/securesms/service/SmsSender.java
@@ -30,9 +30,13 @@ import org.thoughtcrime.securesms.database.model.SmsMessageRecord;
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.sms.IncomingTextMessage;
import org.thoughtcrime.securesms.transport.UndeliverableMessageException;
import org.thoughtcrime.securesms.transport.UniversalTransport;
+import org.thoughtcrime.securesms.transport.UntrustedIdentityException;
import org.whispersystems.textsecure.crypto.MasterSecret;
+import org.whispersystems.textsecure.util.Base64;
public class SmsSender {
@@ -71,12 +75,21 @@ public class SmsSender {
else reader = database.getOutgoingMessages(masterSecret);
while (reader != null && (record = reader.getNext()) != null) {
- database.markAsSending(record.getId());
- transport.deliver(record);
+ try {
+ database.markAsSending(record.getId());
+
+ transport.deliver(record);
+ } catch (UntrustedIdentityException e) {
+ Log.w("SmsSender", e);
+ IncomingTextMessage base = new IncomingTextMessage(record);
+ IncomingIdentityUpdateMessage identityUpdateMessage = new IncomingIdentityUpdateMessage(base, Base64.encodeBytesWithoutPadding(e.getIdentityKey().serialize()));
+ DatabaseFactory.getEncryptingSmsDatabase(context).insertMessageInbox(masterSecret, identityUpdateMessage);
+ DatabaseFactory.getSmsDatabase(context).markAsSentFailed(messageId);
+ } catch (UndeliverableMessageException ude) {
+ Log.w("SmsSender", ude);
+ DatabaseFactory.getSmsDatabase(context).markAsSentFailed(messageId);
+ }
}
- } catch (UndeliverableMessageException ude) {
- Log.w("SmsSender", ude);
- DatabaseFactory.getSmsDatabase(context).markAsSentFailed(messageId);
} finally {
if (reader != null)
reader.close();
diff --git a/src/org/thoughtcrime/securesms/sms/IncomingIdentityUpdateMessage.java b/src/org/thoughtcrime/securesms/sms/IncomingIdentityUpdateMessage.java
new file mode 100644
index 0000000000..e494e691e5
--- /dev/null
+++ b/src/org/thoughtcrime/securesms/sms/IncomingIdentityUpdateMessage.java
@@ -0,0 +1,18 @@
+package org.thoughtcrime.securesms.sms;
+
+public class IncomingIdentityUpdateMessage extends IncomingKeyExchangeMessage {
+
+ public IncomingIdentityUpdateMessage(IncomingTextMessage base, String newBody) {
+ super(base, newBody);
+ }
+
+ @Override
+ public IncomingIdentityUpdateMessage withMessageBody(String messageBody) {
+ return new IncomingIdentityUpdateMessage(this, messageBody);
+ }
+
+ @Override
+ public boolean isIdentityUpdate() {
+ return true;
+ }
+}
diff --git a/src/org/thoughtcrime/securesms/sms/IncomingPreKeyBundleMessage.java b/src/org/thoughtcrime/securesms/sms/IncomingPreKeyBundleMessage.java
index c4103564b0..30ad71dae0 100644
--- a/src/org/thoughtcrime/securesms/sms/IncomingPreKeyBundleMessage.java
+++ b/src/org/thoughtcrime/securesms/sms/IncomingPreKeyBundleMessage.java
@@ -1,7 +1,5 @@
package org.thoughtcrime.securesms.sms;
-import org.whispersystems.textsecure.push.IncomingPushMessage;
-
public class IncomingPreKeyBundleMessage extends IncomingKeyExchangeMessage {
public IncomingPreKeyBundleMessage(IncomingTextMessage base, String newBody) {
diff --git a/src/org/thoughtcrime/securesms/sms/IncomingTextMessage.java b/src/org/thoughtcrime/securesms/sms/IncomingTextMessage.java
index 5c1ec29a5c..71e3ebd861 100644
--- a/src/org/thoughtcrime/securesms/sms/IncomingTextMessage.java
+++ b/src/org/thoughtcrime/securesms/sms/IncomingTextMessage.java
@@ -4,12 +4,15 @@ import android.os.Parcel;
import android.os.Parcelable;
import android.telephony.SmsMessage;
+import org.thoughtcrime.securesms.database.model.SmsMessageRecord;
import org.thoughtcrime.securesms.util.GroupUtil;
import org.whispersystems.textsecure.push.IncomingPushMessage;
import org.whispersystems.textsecure.storage.RecipientDevice;
import java.util.List;
+import ws.com.google.android.mms.pdu.SendReq;
+
import static org.whispersystems.textsecure.push.PushMessageProtos.PushMessageContent.GroupContext;
public class IncomingTextMessage implements Parcelable {
@@ -121,6 +124,34 @@ public class IncomingTextMessage implements Parcelable {
this.groupActionArgument = fragments.get(0).getGroupActionArgument();
}
+ public IncomingTextMessage(SendReq record) {
+ this.message = "";
+ this.sender = record.getTo()[0].getString();
+ this.senderDeviceId = RecipientDevice.DEFAULT_DEVICE_ID;
+ this.protocol = 31338;
+ this.serviceCenterAddress = "Outgoing";
+ this.replyPathPresent = true;
+ this.pseudoSubject = "";
+ this.sentTimestampMillis = System.currentTimeMillis();
+ this.groupId = null;
+ this.groupAction = -1;
+ this.groupActionArgument = null;
+ }
+
+ public IncomingTextMessage(SmsMessageRecord record) {
+ this.message = record.getBody().getBody();
+ this.sender = record.getIndividualRecipient().getNumber();
+ this.senderDeviceId = RecipientDevice.DEFAULT_DEVICE_ID;
+ this.protocol = 31338;
+ this.serviceCenterAddress = "Outgoing";
+ this.replyPathPresent = true;
+ this.pseudoSubject = "";
+ this.sentTimestampMillis = System.currentTimeMillis();
+ this.groupId = null;
+ this.groupAction = -1;
+ this.groupActionArgument = null;
+ }
+
public long getSentTimestampMillis() {
return sentTimestampMillis;
}
@@ -169,6 +200,10 @@ public class IncomingTextMessage implements Parcelable {
return false;
}
+ public boolean isIdentityUpdate() {
+ return false;
+ }
+
public String getGroupId() {
return groupId;
}
diff --git a/src/org/thoughtcrime/securesms/transport/PushTransport.java b/src/org/thoughtcrime/securesms/transport/PushTransport.java
index 34ae9c8594..4c2406450a 100644
--- a/src/org/thoughtcrime/securesms/transport/PushTransport.java
+++ b/src/org/thoughtcrime/securesms/transport/PushTransport.java
@@ -73,7 +73,9 @@ public class PushTransport extends BaseTransport {
this.masterSecret = masterSecret;
}
- public void deliver(SmsMessageRecord message) throws IOException {
+ public void deliver(SmsMessageRecord message)
+ throws IOException, UntrustedIdentityException
+ {
try {
Recipient recipient = message.getIndividualRecipient();
long threadId = message.getThreadId();
@@ -97,7 +99,9 @@ public class PushTransport extends BaseTransport {
}
}
- public void deliver(SendReq message, long threadId) throws IOException {
+ public void deliver(SendReq message, long threadId)
+ throws IOException, UntrustedIdentityException
+ {
PushServiceSocket socket = PushServiceSocketFactory.create(context);
byte[] plaintext = getPlaintextMessage(socket, message);
String destination = message.getTo()[0].getString();
@@ -147,6 +151,9 @@ public class PushTransport extends BaseTransport {
} catch (IOException e) {
Log.w("PushTransport", e);
failures.add(recipient);
+ } catch (UntrustedIdentityException e) {
+ Log.w("PushTransport", e);
+ failures.add(recipient);
}
}
@@ -165,7 +172,7 @@ public class PushTransport extends BaseTransport {
}
private void deliver(PushServiceSocket socket, Recipient recipient, long threadId, byte[] plaintext)
- throws IOException, InvalidNumberException
+ throws IOException, InvalidNumberException, UntrustedIdentityException
{
for (int i=0;i<3;i++) {
try {
@@ -274,7 +281,7 @@ public class PushTransport extends BaseTransport {
private OutgoingPushMessageList getEncryptedMessages(PushServiceSocket socket, long threadId,
Recipient recipient, byte[] plaintext)
- throws IOException, InvalidNumberException
+ throws IOException, InvalidNumberException, UntrustedIdentityException
{
String e164number = Util.canonicalizeNumber(context, recipient.getNumber());
long recipientId = recipient.getRecipientId();
@@ -296,7 +303,7 @@ public class PushTransport extends BaseTransport {
private PushBody getEncryptedMessage(PushServiceSocket socket, long threadId,
PushAddress pushAddress, byte[] plaintext)
- throws IOException
+ throws IOException, UntrustedIdentityException
{
if (!SessionRecordV2.hasSession(context, masterSecret, pushAddress)) {
try {
@@ -306,7 +313,11 @@ public class PushTransport extends BaseTransport {
PushAddress device = PushAddress.create(context, pushAddress.getRecipientId(), pushAddress.getNumber(), preKey.getDeviceId());
KeyExchangeProcessorV2 processor = new KeyExchangeProcessorV2(context, masterSecret, device);
- processor.processKeyExchangeMessage(preKey, threadId);
+ if (processor.isTrusted(preKey)) {
+ processor.processKeyExchangeMessage(preKey, threadId);
+ } else {
+ throw new UntrustedIdentityException("Untrusted identity key!", preKey.getIdentityKey());
+ }
}
} catch (InvalidKeyException e) {
throw new IOException(e);
diff --git a/src/org/thoughtcrime/securesms/transport/UniversalTransport.java b/src/org/thoughtcrime/securesms/transport/UniversalTransport.java
index 3554364c52..d948c77416 100644
--- a/src/org/thoughtcrime/securesms/transport/UniversalTransport.java
+++ b/src/org/thoughtcrime/securesms/transport/UniversalTransport.java
@@ -18,7 +18,6 @@ package org.thoughtcrime.securesms.transport;
import android.content.Context;
import android.util.Log;
-import android.widget.Toast;
import org.thoughtcrime.securesms.database.model.SmsMessageRecord;
import org.thoughtcrime.securesms.mms.MmsSendResult;
@@ -54,7 +53,9 @@ public class UniversalTransport {
this.mmsTransport = new MmsTransport(context, masterSecret);
}
- public void deliver(SmsMessageRecord message) throws UndeliverableMessageException {
+ public void deliver(SmsMessageRecord message)
+ throws UndeliverableMessageException, UntrustedIdentityException
+ {
if (!TextSecurePreferences.isPushRegistered(context)) {
smsTransport.deliver(message);
return;
@@ -83,7 +84,7 @@ public class UniversalTransport {
}
public MmsSendResult deliver(SendReq mediaMessage, long threadId)
- throws UndeliverableMessageException, RetryLaterException
+ throws UndeliverableMessageException, RetryLaterException, UntrustedIdentityException
{
if (Util.isEmpty(mediaMessage.getTo())) {
throw new UndeliverableMessageException("No destination specified");
@@ -97,14 +98,23 @@ public class UniversalTransport {
return mmsTransport.deliver(mediaMessage);
}
- if (isPushTransport(mediaMessage.getTo()[0].getString())) {
+ String destination;
+
+ try {
+ destination = Util.canonicalizeNumber(context, mediaMessage.getTo()[0].getString());
+ } catch (InvalidNumberException ine) {
+ Log.w("UniversalTransport", ine);
+ return mmsTransport.deliver(mediaMessage);
+ }
+
+ if (isPushTransport(destination)) {
try {
Log.w("UniversalTransport", "Delivering media message with GCM...");
pushTransport.deliver(mediaMessage, threadId);
return new MmsSendResult("push".getBytes("UTF-8"), 0, true);
} catch (IOException ioe) {
Log.w("UniversalTransport", ioe);
- if (!GroupUtil.isEncodedGroup(mediaMessage.getTo()[0].getString())) {
+ if (!GroupUtil.isEncodedGroup(destination)) {
return mmsTransport.deliver(mediaMessage);
} else {
throw new RetryLaterException();
diff --git a/src/org/thoughtcrime/securesms/transport/UntrustedIdentityException.java b/src/org/thoughtcrime/securesms/transport/UntrustedIdentityException.java
new file mode 100644
index 0000000000..e14f79332f
--- /dev/null
+++ b/src/org/thoughtcrime/securesms/transport/UntrustedIdentityException.java
@@ -0,0 +1,17 @@
+package org.thoughtcrime.securesms.transport;
+
+import org.whispersystems.textsecure.crypto.IdentityKey;
+
+public class UntrustedIdentityException extends Exception {
+
+ private final IdentityKey identityKey;
+
+ public UntrustedIdentityException(String s, IdentityKey identityKey) {
+ super(s);
+ this.identityKey = identityKey;
+ }
+
+ public IdentityKey getIdentityKey() {
+ return identityKey;
+ }
+}