From 99f42e2ee16e6b246a7923e91413a305703074ae Mon Sep 17 00:00:00 2001 From: Moxie Marlinspike Date: Tue, 4 Nov 2014 15:01:32 -0800 Subject: [PATCH] Move API around. --- .../api/TextSecureMessageReceiver.java | 116 -------------- .../api/TextSecureMessageSender.java | 4 +- .../messages/TextSecureAttachmentStream.java | 4 +- .../messages/TextSecureEnvelope.java} | 93 ++++++++--- .../textsecure/crypto/TextSecureCipher.java | 111 +++++++++++-- .../textsecure/push/IncomingPushMessage.java | 149 ------------------ .../securesms/database/PushDatabase.java | 41 +++-- .../groups/GroupMessageProcessor.java | 32 ++-- .../securesms/jobs/PushDecryptJob.java | 112 ++++++------- .../securesms/jobs/PushReceiveJob.java | 34 ++-- .../securesms/mms/IncomingMediaMessage.java | 6 +- .../notifications/MessageNotifier.java | 24 +-- .../recipients/RecipientFactory.java | 13 -- .../securesms/service/MmsSender.java | 2 +- .../securesms/sms/IncomingTextMessage.java | 3 - .../securesms/transport/PushTransport.java | 7 +- .../transport/UniversalTransport.java | 10 +- 17 files changed, 303 insertions(+), 458 deletions(-) rename library/src/org/whispersystems/textsecure/{push/IncomingEncryptedPushMessage.java => api/messages/TextSecureEnvelope.java} (63%) delete mode 100644 library/src/org/whispersystems/textsecure/push/IncomingPushMessage.java diff --git a/library/src/org/whispersystems/textsecure/api/TextSecureMessageReceiver.java b/library/src/org/whispersystems/textsecure/api/TextSecureMessageReceiver.java index 81c7c21e3c..e4b6a02beb 100644 --- a/library/src/org/whispersystems/textsecure/api/TextSecureMessageReceiver.java +++ b/library/src/org/whispersystems/textsecure/api/TextSecureMessageReceiver.java @@ -2,40 +2,15 @@ package org.whispersystems.textsecure.api; import android.content.Context; -import com.google.protobuf.InvalidProtocolBufferException; - -import org.whispersystems.libaxolotl.DuplicateMessageException; -import org.whispersystems.libaxolotl.InvalidKeyException; -import org.whispersystems.libaxolotl.InvalidKeyIdException; import org.whispersystems.libaxolotl.InvalidMessageException; -import org.whispersystems.libaxolotl.InvalidVersionException; -import org.whispersystems.libaxolotl.LegacyMessageException; -import org.whispersystems.libaxolotl.NoSessionException; -import org.whispersystems.libaxolotl.UntrustedIdentityException; -import org.whispersystems.libaxolotl.protocol.PreKeyWhisperMessage; -import org.whispersystems.libaxolotl.protocol.WhisperMessage; import org.whispersystems.libaxolotl.state.AxolotlStore; -import org.whispersystems.libaxolotl.util.guava.Optional; -import org.whispersystems.textsecure.api.messages.TextSecureAttachment; import org.whispersystems.textsecure.api.messages.TextSecureAttachmentPointer; -import org.whispersystems.textsecure.api.messages.TextSecureGroup; -import org.whispersystems.textsecure.api.messages.TextSecureMessage; import org.whispersystems.textsecure.crypto.AttachmentCipherInputStream; -import org.whispersystems.textsecure.crypto.TextSecureCipher; -import org.whispersystems.textsecure.push.IncomingEncryptedPushMessage; -import org.whispersystems.textsecure.push.IncomingPushMessage; -import org.whispersystems.textsecure.push.PushAddress; import org.whispersystems.textsecure.push.PushServiceSocket; import java.io.File; import java.io.IOException; import java.io.InputStream; -import java.util.LinkedList; -import java.util.List; - -import static org.whispersystems.textsecure.push.PushMessageProtos.PushMessageContent; -import static org.whispersystems.textsecure.push.PushMessageProtos.PushMessageContent.AttachmentPointer; -import static org.whispersystems.textsecure.push.PushMessageProtos.PushMessageContent.GroupContext.Type.DELIVER; public class TextSecureMessageReceiver { @@ -61,95 +36,4 @@ public class TextSecureMessageReceiver { return new AttachmentCipherInputStream(destination, pointer.getKey()); } - public IncomingPushMessage receiveSignal(String signal) - throws IOException, InvalidVersionException - { - IncomingEncryptedPushMessage encrypted = new IncomingEncryptedPushMessage(signal, signalingKey); - return encrypted.getIncomingPushMessage(); - } - - public TextSecureMessage receiveMessage(long recipientId, IncomingPushMessage signal) - throws InvalidVersionException, InvalidMessageException, NoSessionException, - LegacyMessageException, InvalidKeyIdException, DuplicateMessageException, - InvalidKeyException, UntrustedIdentityException - { - try { - PushAddress sender = new PushAddress(recipientId, signal.getSource(), signal.getSourceDevice(), signal.getRelay()); - TextSecureCipher cipher = new TextSecureCipher(axolotlStore, sender); - - PushMessageContent message; - - if (signal.isPreKeyBundle()) { - PreKeyWhisperMessage bundle = new PreKeyWhisperMessage(signal.getBody()); - message = PushMessageContent.parseFrom(cipher.decrypt(bundle)); - } else if (signal.isSecureMessage()) { - WhisperMessage ciphertext = new WhisperMessage(signal.getBody()); - message = PushMessageContent.parseFrom(cipher.decrypt(ciphertext)); - } else if (signal.isPlaintext()) { - message = PushMessageContent.parseFrom(signal.getBody()); - } else { - throw new InvalidMessageException("Unknown type: " + signal.getType()); - } - - return createTextSecureMessage(signal, message); - } catch (InvalidProtocolBufferException e) { - throw new InvalidMessageException(e); - } - } - - private TextSecureMessage createTextSecureMessage(IncomingPushMessage signal, PushMessageContent content) { - TextSecureGroup groupInfo = createGroupInfo(signal, content); - List attachments = new LinkedList<>(); - boolean endSession = ((content.getFlags() & PushMessageContent.Flags.END_SESSION_VALUE) != 0); - boolean secure = signal.isSecureMessage() || signal.isPreKeyBundle(); - - for (AttachmentPointer pointer : content.getAttachmentsList()) { - attachments.add(new TextSecureAttachmentPointer(pointer.getId(), - pointer.getContentType(), - pointer.getKey().toByteArray(), - signal.getRelay())); - } - - return new TextSecureMessage(signal.getTimestampMillis(), groupInfo, attachments, - content.getBody(), secure, endSession); - } - - private TextSecureGroup createGroupInfo(IncomingPushMessage signal, PushMessageContent content) { - if (!content.hasGroup()) return null; - - TextSecureGroup.Type type; - - switch (content.getGroup().getType()) { - case DELIVER: type = TextSecureGroup.Type.DELIVER; break; - case UPDATE: type = TextSecureGroup.Type.UPDATE; break; - case QUIT: type = TextSecureGroup.Type.QUIT; break; - default: type = TextSecureGroup.Type.UNKNOWN; break; - } - - if (content.getGroup().getType() != DELIVER) { - String name = null; - List members = null; - TextSecureAttachmentPointer avatar = null; - - if (content.getGroup().hasName()) { - name = content.getGroup().getName(); - } - - if (content.getGroup().getMembersCount() > 0) { - members = content.getGroup().getMembersList(); - } - - if (content.getGroup().hasAvatar()) { - avatar = new TextSecureAttachmentPointer(content.getGroup().getAvatar().getId(), - content.getGroup().getAvatar().getContentType(), - content.getGroup().getAvatar().getKey().toByteArray(), - signal.getRelay()); - } - - return new TextSecureGroup(type, content.getGroup().getId().toByteArray(), name, members, avatar); - } - - return new TextSecureGroup(content.getGroup().getId().toByteArray()); - } - } diff --git a/library/src/org/whispersystems/textsecure/api/TextSecureMessageSender.java b/library/src/org/whispersystems/textsecure/api/TextSecureMessageSender.java index 37515000a6..691683e599 100644 --- a/library/src/org/whispersystems/textsecure/api/TextSecureMessageSender.java +++ b/library/src/org/whispersystems/textsecure/api/TextSecureMessageSender.java @@ -173,11 +173,13 @@ public class TextSecureMessageSender { List pointers = new LinkedList<>(); if (!attachments.isPresent() || attachments.get().isEmpty()) { + Log.w(TAG, "No attachments present..."); return pointers; } for (TextSecureAttachment attachment : attachments.get()) { if (attachment.isStream()) { + Log.w(TAG, "Found attachment, creating pointer..."); pointers.add(createAttachmentPointer(attachment.asStream())); } } @@ -249,7 +251,7 @@ public class TextSecureMessageSender { } } - TextSecureCipher cipher = new TextSecureCipher(store, recipient); + TextSecureCipher cipher = new TextSecureCipher(store, recipient.getRecipientId(), recipient.getDeviceId()); CiphertextMessage message = cipher.encrypt(plaintext); int remoteRegistrationId = cipher.getRemoteRegistrationId(); diff --git a/library/src/org/whispersystems/textsecure/api/messages/TextSecureAttachmentStream.java b/library/src/org/whispersystems/textsecure/api/messages/TextSecureAttachmentStream.java index 1e54494fd5..fbcf6d1db4 100644 --- a/library/src/org/whispersystems/textsecure/api/messages/TextSecureAttachmentStream.java +++ b/library/src/org/whispersystems/textsecure/api/messages/TextSecureAttachmentStream.java @@ -15,12 +15,12 @@ public class TextSecureAttachmentStream extends TextSecureAttachment { @Override public boolean isStream() { - return false; + return true; } @Override public boolean isPointer() { - return true; + return false; } public InputStream getInputStream() { diff --git a/library/src/org/whispersystems/textsecure/push/IncomingEncryptedPushMessage.java b/library/src/org/whispersystems/textsecure/api/messages/TextSecureEnvelope.java similarity index 63% rename from library/src/org/whispersystems/textsecure/push/IncomingEncryptedPushMessage.java rename to library/src/org/whispersystems/textsecure/api/messages/TextSecureEnvelope.java index bd3df0fc5e..bbfc09ff32 100644 --- a/library/src/org/whispersystems/textsecure/push/IncomingEncryptedPushMessage.java +++ b/library/src/org/whispersystems/textsecure/api/messages/TextSecureEnvelope.java @@ -1,12 +1,20 @@ -package org.whispersystems.textsecure.push; +package org.whispersystems.textsecure.api.messages; import android.util.Log; +import com.google.protobuf.ByteString; + import org.whispersystems.libaxolotl.InvalidVersionException; -import org.whispersystems.textsecure.util.Base64; import org.whispersystems.textsecure.push.PushMessageProtos.IncomingPushMessageSignal; +import org.whispersystems.textsecure.util.Base64; import org.whispersystems.textsecure.util.Hex; +import java.io.IOException; +import java.security.InvalidAlgorithmParameterException; +import java.security.InvalidKeyException; +import java.security.NoSuchAlgorithmException; +import java.util.Arrays; + import javax.crypto.BadPaddingException; import javax.crypto.Cipher; import javax.crypto.IllegalBlockSizeException; @@ -14,13 +22,10 @@ import javax.crypto.Mac; import javax.crypto.NoSuchPaddingException; import javax.crypto.spec.IvParameterSpec; import javax.crypto.spec.SecretKeySpec; -import java.io.IOException; -import java.security.InvalidAlgorithmParameterException; -import java.security.InvalidKeyException; -import java.security.NoSuchAlgorithmException; -import java.util.Arrays; -public class IncomingEncryptedPushMessage { +public class TextSecureEnvelope { + + private static final String TAG = TextSecureEnvelope.class.getSimpleName(); private static final int SUPPORTED_VERSION = 1; private static final int CIPHER_KEY_SIZE = 32; @@ -33,9 +38,9 @@ public class IncomingEncryptedPushMessage { private static final int IV_LENGTH = 16; private static final int CIPHERTEXT_OFFSET = IV_OFFSET + IV_LENGTH; - private final IncomingPushMessage incomingPushMessage; + private final IncomingPushMessageSignal signal; - public IncomingEncryptedPushMessage(String message, String signalingKey) + public TextSecureEnvelope(String message, String signalingKey) throws IOException, InvalidVersionException { byte[] ciphertext = Base64.decode(message); @@ -48,14 +53,60 @@ public class IncomingEncryptedPushMessage { verifyMac(ciphertext, macKey); - byte[] plaintext = getPlaintext(ciphertext, cipherKey); - IncomingPushMessageSignal signal = IncomingPushMessageSignal.parseFrom(plaintext); - - this.incomingPushMessage = new IncomingPushMessage(signal); + this.signal = IncomingPushMessageSignal.parseFrom(getPlaintext(ciphertext, cipherKey)); } - public IncomingPushMessage getIncomingPushMessage() { - return incomingPushMessage; + public TextSecureEnvelope(int type, String source, int sourceDevice, + String relay, long timestamp, byte[] message) + { + this.signal = IncomingPushMessageSignal.newBuilder() + .setType(IncomingPushMessageSignal.Type.valueOf(type)) + .setSource(source) + .setSourceDevice(sourceDevice) + .setRelay(relay) + .setTimestamp(timestamp) + .setMessage(ByteString.copyFrom(message)) + .build(); + } + + public String getSource() { + return signal.getSource(); + } + + public int getSourceDevice() { + return signal.getSourceDevice(); + } + + public int getType() { + return signal.getType().getNumber(); + } + + public String getRelay() { + return signal.getRelay(); + } + + public long getTimestamp() { + return signal.getTimestamp(); + } + + public byte[] getMessage() { + return signal.getMessage().toByteArray(); + } + + public boolean isWhisperMessage() { + return signal.getType().getNumber() == IncomingPushMessageSignal.Type.CIPHERTEXT_VALUE; + } + + public boolean isPreKeyWhisperMessage() { + return signal.getType().getNumber() == IncomingPushMessageSignal.Type.PREKEY_BUNDLE_VALUE; + } + + public boolean isPlaintext() { + return signal.getType().getNumber() == IncomingPushMessageSignal.Type.PLAINTEXT_VALUE; + } + + public boolean isReceipt() { + return signal.getType().getNumber() == IncomingPushMessageSignal.Type.RECEIPT_VALUE; } private byte[] getPlaintext(byte[] ciphertext, SecretKeySpec cipherKey) throws IOException { @@ -72,7 +123,7 @@ public class IncomingEncryptedPushMessage { } catch (NoSuchAlgorithmException | NoSuchPaddingException | InvalidKeyException | InvalidAlgorithmParameterException | IllegalBlockSizeException e) { throw new AssertionError(e); } catch (BadPaddingException e) { - Log.w("IncomingEncryptedPushMessage", e); + Log.w(TAG, e); throw new IOException("Bad padding?"); } } @@ -94,15 +145,13 @@ public class IncomingEncryptedPushMessage { byte[] theirMacBytes = new byte[MAC_SIZE]; System.arraycopy(ciphertext, ciphertext.length-MAC_SIZE, theirMacBytes, 0, theirMacBytes.length); - Log.w("IncomingEncryptedPushMessage", "Our MAC: " + Hex.toString(ourMacBytes)); - Log.w("IncomingEncryptedPushMessage", "Thr MAC: " + Hex.toString(theirMacBytes)); + Log.w(TAG, "Our MAC: " + Hex.toString(ourMacBytes)); + Log.w(TAG, "Thr MAC: " + Hex.toString(theirMacBytes)); if (!Arrays.equals(ourMacBytes, theirMacBytes)) { throw new IOException("Invalid MAC compare!"); } - } catch (NoSuchAlgorithmException e) { - throw new AssertionError(e); - } catch (InvalidKeyException e) { + } catch (NoSuchAlgorithmException | InvalidKeyException e) { throw new AssertionError(e); } } diff --git a/library/src/org/whispersystems/textsecure/crypto/TextSecureCipher.java b/library/src/org/whispersystems/textsecure/crypto/TextSecureCipher.java index 1c4109397a..dcf238f1e3 100644 --- a/library/src/org/whispersystems/textsecure/crypto/TextSecureCipher.java +++ b/library/src/org/whispersystems/textsecure/crypto/TextSecureCipher.java @@ -1,9 +1,12 @@ package org.whispersystems.textsecure.crypto; +import com.google.protobuf.InvalidProtocolBufferException; + import org.whispersystems.libaxolotl.DuplicateMessageException; import org.whispersystems.libaxolotl.InvalidKeyException; import org.whispersystems.libaxolotl.InvalidKeyIdException; import org.whispersystems.libaxolotl.InvalidMessageException; +import org.whispersystems.libaxolotl.InvalidVersionException; import org.whispersystems.libaxolotl.LegacyMessageException; import org.whispersystems.libaxolotl.NoSessionException; import org.whispersystems.libaxolotl.SessionCipher; @@ -12,46 +15,120 @@ import org.whispersystems.libaxolotl.protocol.CiphertextMessage; import org.whispersystems.libaxolotl.protocol.PreKeyWhisperMessage; import org.whispersystems.libaxolotl.protocol.WhisperMessage; import org.whispersystems.libaxolotl.state.AxolotlStore; -import org.whispersystems.textsecure.push.PushAddress; +import org.whispersystems.textsecure.api.messages.TextSecureAttachment; +import org.whispersystems.textsecure.api.messages.TextSecureAttachmentPointer; +import org.whispersystems.textsecure.api.messages.TextSecureEnvelope; +import org.whispersystems.textsecure.api.messages.TextSecureGroup; +import org.whispersystems.textsecure.api.messages.TextSecureMessage; import org.whispersystems.textsecure.push.PushTransportDetails; +import java.util.LinkedList; +import java.util.List; + +import static org.whispersystems.textsecure.push.PushMessageProtos.PushMessageContent; +import static org.whispersystems.textsecure.push.PushMessageProtos.PushMessageContent.GroupContext.Type.DELIVER; + public class TextSecureCipher { private final SessionCipher sessionCipher; private final TransportDetails transportDetails; - public TextSecureCipher(AxolotlStore axolotlStore, PushAddress pushAddress) { - int sessionVersion = axolotlStore.loadSession(pushAddress.getRecipientId(), - pushAddress.getDeviceId()) + public TextSecureCipher(AxolotlStore axolotlStore, long recipientId, int deviceId) { + int sessionVersion = axolotlStore.loadSession(recipientId, deviceId) .getSessionState().getSessionVersion(); this.transportDetails = new PushTransportDetails(sessionVersion); - this.sessionCipher = new SessionCipher(axolotlStore, pushAddress.getRecipientId(), - pushAddress.getDeviceId()); + this.sessionCipher = new SessionCipher(axolotlStore, recipientId, deviceId); } public CiphertextMessage encrypt(byte[] unpaddedMessage) { return sessionCipher.encrypt(transportDetails.getPaddedMessageBody(unpaddedMessage)); } - public byte[] decrypt(WhisperMessage message) - throws DuplicateMessageException, LegacyMessageException, InvalidMessageException, NoSessionException + public TextSecureMessage decrypt(TextSecureEnvelope envelope) + throws InvalidVersionException, InvalidMessageException, InvalidKeyException, + DuplicateMessageException, InvalidKeyIdException, UntrustedIdentityException, + LegacyMessageException, NoSessionException { - byte[] paddedMessage = sessionCipher.decrypt(message); - return transportDetails.getStrippedPaddingMessageBody(paddedMessage); - } + try { + byte[] paddedMessage; - public byte[] decrypt(PreKeyWhisperMessage message) - throws InvalidKeyException, LegacyMessageException, InvalidMessageException, - DuplicateMessageException, InvalidKeyIdException, UntrustedIdentityException, NoSessionException - { - byte[] paddedMessage = sessionCipher.decrypt(message); - return transportDetails.getStrippedPaddingMessageBody(paddedMessage); + if (envelope.isPreKeyWhisperMessage()) { + paddedMessage = sessionCipher.decrypt(new PreKeyWhisperMessage(envelope.getMessage())); + } else if (envelope.isWhisperMessage()) { + paddedMessage = sessionCipher.decrypt(new WhisperMessage(envelope.getMessage())); + } else if (envelope.isPlaintext()) { + paddedMessage = envelope.getMessage(); + } else { + throw new InvalidMessageException("Unknown type: " + envelope.getType()); + } + + PushMessageContent content = PushMessageContent.parseFrom(transportDetails.getStrippedPaddingMessageBody(paddedMessage)); + return createTextSecureMessage(envelope, content); + } catch (InvalidProtocolBufferException e) { + throw new InvalidMessageException(e); + } } public int getRemoteRegistrationId() { return sessionCipher.getRemoteRegistrationId(); } + private TextSecureMessage createTextSecureMessage(TextSecureEnvelope envelope, PushMessageContent content) { + TextSecureGroup groupInfo = createGroupInfo(envelope, content); + List attachments = new LinkedList<>(); + boolean endSession = ((content.getFlags() & PushMessageContent.Flags.END_SESSION_VALUE) != 0); + boolean secure = envelope.isWhisperMessage() || envelope.isPreKeyWhisperMessage(); + + for (PushMessageContent.AttachmentPointer pointer : content.getAttachmentsList()) { + attachments.add(new TextSecureAttachmentPointer(pointer.getId(), + pointer.getContentType(), + pointer.getKey().toByteArray(), + envelope.getRelay())); + } + + return new TextSecureMessage(envelope.getTimestamp(), groupInfo, attachments, + content.getBody(), secure, endSession); + } + + private TextSecureGroup createGroupInfo(TextSecureEnvelope envelope, PushMessageContent content) { + if (!content.hasGroup()) return null; + + TextSecureGroup.Type type; + + switch (content.getGroup().getType()) { + case DELIVER: type = TextSecureGroup.Type.DELIVER; break; + case UPDATE: type = TextSecureGroup.Type.UPDATE; break; + case QUIT: type = TextSecureGroup.Type.QUIT; break; + default: type = TextSecureGroup.Type.UNKNOWN; break; + } + + if (content.getGroup().getType() != DELIVER) { + String name = null; + List members = null; + TextSecureAttachmentPointer avatar = null; + + if (content.getGroup().hasName()) { + name = content.getGroup().getName(); + } + + if (content.getGroup().getMembersCount() > 0) { + members = content.getGroup().getMembersList(); + } + + if (content.getGroup().hasAvatar()) { + avatar = new TextSecureAttachmentPointer(content.getGroup().getAvatar().getId(), + content.getGroup().getAvatar().getContentType(), + content.getGroup().getAvatar().getKey().toByteArray(), + envelope.getRelay()); + } + + return new TextSecureGroup(type, content.getGroup().getId().toByteArray(), name, members, avatar); + } + + return new TextSecureGroup(content.getGroup().getId().toByteArray()); + } + + } diff --git a/library/src/org/whispersystems/textsecure/push/IncomingPushMessage.java b/library/src/org/whispersystems/textsecure/push/IncomingPushMessage.java deleted file mode 100644 index e04b96587d..0000000000 --- a/library/src/org/whispersystems/textsecure/push/IncomingPushMessage.java +++ /dev/null @@ -1,149 +0,0 @@ -/** - * Copyright (C) 2013 Open Whisper Systems - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ -package org.whispersystems.textsecure.push; - -import android.os.Parcel; -import android.os.Parcelable; - -import org.whispersystems.textsecure.push.PushMessageProtos.IncomingPushMessageSignal; - -public class IncomingPushMessage implements Parcelable { - - public static final Parcelable.Creator CREATOR = new Parcelable.Creator() { - @Override - public IncomingPushMessage createFromParcel(Parcel in) { - return new IncomingPushMessage(in); - } - - @Override - public IncomingPushMessage[] newArray(int size) { - return new IncomingPushMessage[size]; - } - }; - - private int type; - private String source; - private int sourceDevice; - private byte[] message; - private long timestamp; - private String relay; - - private IncomingPushMessage(IncomingPushMessage message, byte[] body) { - this.type = message.type; - this.source = message.source; - this.sourceDevice = message.sourceDevice; - this.timestamp = message.timestamp; - this.relay = message.relay; - this.message = body; - } - - public IncomingPushMessage(IncomingPushMessageSignal signal) { - this.type = signal.getType().getNumber(); - this.source = signal.getSource(); - this.sourceDevice = signal.getSourceDevice(); - this.message = signal.getMessage().toByteArray(); - this.timestamp = signal.getTimestamp(); - this.relay = signal.getRelay(); - } - - public IncomingPushMessage(Parcel in) { - this.type = in.readInt(); - this.source = in.readString(); - this.sourceDevice = in.readInt(); - - if (in.readInt() == 1) { - this.relay = in.readString(); - } - - this.message = new byte[in.readInt()]; - in.readByteArray(this.message); - this.timestamp = in.readLong(); - } - - public IncomingPushMessage(int type, String source, int sourceDevice, - byte[] body, long timestamp) - { - this.type = type; - this.source = source; - this.sourceDevice = sourceDevice; - this.message = body; - this.timestamp = timestamp; - } - - public String getRelay() { - return relay; - } - - public long getTimestampMillis() { - return timestamp; - } - - public String getSource() { - return source; - } - - public int getSourceDevice() { - return sourceDevice; - } - - public byte[] getBody() { - return message; - } - - @Override - public int describeContents() { - return 0; - } - - @Override - public void writeToParcel(Parcel dest, int flags) { - dest.writeInt(type); - dest.writeString(source); - dest.writeInt(sourceDevice); - dest.writeInt(relay == null ? 0 : 1); - if (relay != null) { - dest.writeString(relay); - } - dest.writeInt(message.length); - dest.writeByteArray(message); - dest.writeLong(timestamp); - } - - public IncomingPushMessage withBody(byte[] body) { - return new IncomingPushMessage(this, body); - } - - public int getType() { - return type; - } - - public boolean isSecureMessage() { - return getType() == IncomingPushMessageSignal.Type.CIPHERTEXT_VALUE; - } - - public boolean isPreKeyBundle() { - return getType() == IncomingPushMessageSignal.Type.PREKEY_BUNDLE_VALUE; - } - - public boolean isReceipt() { - return getType() == IncomingPushMessageSignal.Type.RECEIPT_VALUE; - } - - public boolean isPlaintext() { - return getType() == IncomingPushMessageSignal.Type.PLAINTEXT_VALUE; - } -} diff --git a/src/org/thoughtcrime/securesms/database/PushDatabase.java b/src/org/thoughtcrime/securesms/database/PushDatabase.java index 6056659141..b69c1af35a 100644 --- a/src/org/thoughtcrime/securesms/database/PushDatabase.java +++ b/src/org/thoughtcrime/securesms/database/PushDatabase.java @@ -6,15 +6,15 @@ import android.database.Cursor; import android.database.sqlite.SQLiteOpenHelper; import android.util.Log; -import org.whispersystems.textsecure.push.IncomingPushMessage; +import org.whispersystems.textsecure.api.messages.TextSecureEnvelope; import org.whispersystems.textsecure.util.Base64; -import org.whispersystems.textsecure.util.Util; import java.io.IOException; -import java.util.List; public class PushDatabase extends Database { + private static final String TAG = PushDatabase.class.getSimpleName(); + private static final String TABLE_NAME = "push"; public static final String ID = "_id"; public static final String TYPE = "type"; @@ -30,18 +30,18 @@ public class PushDatabase extends Database { super(context, databaseHelper); } - public long insert(IncomingPushMessage message) { + public long insert(TextSecureEnvelope envelope) { ContentValues values = new ContentValues(); - values.put(TYPE, message.getType()); - values.put(SOURCE, message.getSource()); - values.put(DEVICE_ID, message.getSourceDevice()); - values.put(BODY, Base64.encodeBytes(message.getBody())); - values.put(TIMESTAMP, message.getTimestampMillis()); + values.put(TYPE, envelope.getType()); + values.put(SOURCE, envelope.getSource()); + values.put(DEVICE_ID, envelope.getSourceDevice()); + values.put(BODY, Base64.encodeBytes(envelope.getMessage())); + values.put(TIMESTAMP, envelope.getTimestamp()); return databaseHelper.getWritableDatabase().insert(TABLE_NAME, null, values); } - public IncomingPushMessage get(long id) throws NoSuchMessageException { + public TextSecureEnvelope get(long id) throws NoSuchMessageException { Cursor cursor = null; try { @@ -50,14 +50,15 @@ public class PushDatabase extends Database { null, null, null); if (cursor != null && cursor.moveToNext()) { - return new IncomingPushMessage(cursor.getInt(cursor.getColumnIndexOrThrow(TYPE)), - cursor.getString(cursor.getColumnIndexOrThrow(SOURCE)), - cursor.getInt(cursor.getColumnIndexOrThrow(DEVICE_ID)), - Base64.decode(cursor.getString(cursor.getColumnIndexOrThrow(BODY))), - cursor.getLong(cursor.getColumnIndexOrThrow(TIMESTAMP))); + return new TextSecureEnvelope(cursor.getInt(cursor.getColumnIndexOrThrow(TYPE)), + cursor.getString(cursor.getColumnIndexOrThrow(SOURCE)), + cursor.getInt(cursor.getColumnIndexOrThrow(DEVICE_ID)), + "", + cursor.getLong(cursor.getColumnIndexOrThrow(TIMESTAMP)), + Base64.decode(cursor.getString(cursor.getColumnIndexOrThrow(BODY)))); } } catch (IOException e) { - Log.w("PushDatabase", e); + Log.w(TAG, e); throw new NoSuchMessageException(e); } finally { if (cursor != null) @@ -86,7 +87,7 @@ public class PushDatabase extends Database { this.cursor = cursor; } - public IncomingPushMessage getNext() { + public TextSecureEnvelope getNext() { try { if (cursor == null || !cursor.moveToNext()) return null; @@ -97,16 +98,12 @@ public class PushDatabase extends Database { byte[] body = Base64.decode(cursor.getString(cursor.getColumnIndexOrThrow(BODY))); long timestamp = cursor.getLong(cursor.getColumnIndexOrThrow(TIMESTAMP)); - return new IncomingPushMessage(type, source, deviceId, body, timestamp); + return new TextSecureEnvelope(type, source, deviceId, "", timestamp, body); } catch (IOException e) { throw new AssertionError(e); } } - public long getCurrentId() { - return cursor.getLong(cursor.getColumnIndexOrThrow(ID)); - } - public void close() { this.cursor.close(); } diff --git a/src/org/thoughtcrime/securesms/groups/GroupMessageProcessor.java b/src/org/thoughtcrime/securesms/groups/GroupMessageProcessor.java index 33d9e6207d..8686692fee 100644 --- a/src/org/thoughtcrime/securesms/groups/GroupMessageProcessor.java +++ b/src/org/thoughtcrime/securesms/groups/GroupMessageProcessor.java @@ -18,9 +18,9 @@ import org.thoughtcrime.securesms.sms.IncomingGroupMessage; import org.thoughtcrime.securesms.sms.IncomingTextMessage; import org.whispersystems.libaxolotl.util.guava.Optional; import org.whispersystems.textsecure.api.messages.TextSecureAttachment; +import org.whispersystems.textsecure.api.messages.TextSecureEnvelope; import org.whispersystems.textsecure.api.messages.TextSecureGroup; import org.whispersystems.textsecure.api.messages.TextSecureMessage; -import org.whispersystems.textsecure.push.IncomingPushMessage; import org.whispersystems.textsecure.util.Base64; import java.util.HashSet; @@ -38,7 +38,7 @@ public class GroupMessageProcessor { public static void process(Context context, MasterSecret masterSecret, - IncomingPushMessage push, + TextSecureEnvelope envelope, TextSecureMessage message) { if (!message.getGroupInfo().isPresent() || message.getGroupInfo().get().getGroupId() == null) { @@ -57,11 +57,11 @@ public class GroupMessageProcessor { GroupRecord record = database.getGroup(id); if (record != null && group.getType() == TextSecureGroup.Type.UPDATE) { - handleGroupUpdate(context, masterSecret, push, group, record); + handleGroupUpdate(context, masterSecret, envelope, group, record); } else if (record == null && group.getType() == TextSecureGroup.Type.UPDATE) { - handleGroupCreate(context, masterSecret, push, group); + handleGroupCreate(context, masterSecret, envelope, group); } else if (record != null && group.getType() == TextSecureGroup.Type.QUIT) { - handleGroupLeave(context, masterSecret, push, group, record); + handleGroupLeave(context, masterSecret, envelope, group, record); } else { Log.w(TAG, "Received unknown type, ignoring..."); } @@ -69,7 +69,7 @@ public class GroupMessageProcessor { private static void handleGroupCreate(Context context, MasterSecret masterSecret, - IncomingPushMessage message, + TextSecureEnvelope envelope, TextSecureGroup group) { GroupDatabase database = DatabaseFactory.getGroupDatabase(context); @@ -81,14 +81,14 @@ public class GroupMessageProcessor { database.create(id, group.getName().orNull(), group.getMembers().orNull(), avatar != null && avatar.isPointer() ? avatar.asPointer() : null, - message.getRelay()); + envelope.getRelay()); - storeMessage(context, masterSecret, message, group, builder.build()); + storeMessage(context, masterSecret, envelope, group, builder.build()); } private static void handleGroupUpdate(Context context, MasterSecret masterSecret, - IncomingPushMessage push, + TextSecureEnvelope envelope, TextSecureGroup group, GroupRecord groupRecord) { @@ -133,12 +133,12 @@ public class GroupMessageProcessor { if (!groupRecord.isActive()) database.setActive(id, true); - storeMessage(context, masterSecret, push, group, builder.build()); + storeMessage(context, masterSecret, envelope, group, builder.build()); } private static void handleGroupLeave(Context context, MasterSecret masterSecret, - IncomingPushMessage message, + TextSecureEnvelope envelope, TextSecureGroup group, GroupRecord record) { @@ -149,16 +149,16 @@ public class GroupMessageProcessor { GroupContext.Builder builder = createGroupContext(group); builder.setType(GroupContext.Type.QUIT); - if (members.contains(message.getSource())) { - database.remove(id, message.getSource()); + if (members.contains(envelope.getSource())) { + database.remove(id, envelope.getSource()); - storeMessage(context, masterSecret, message, group, builder.build()); + storeMessage(context, masterSecret, envelope, group, builder.build()); } } private static void storeMessage(Context context, MasterSecret masterSecret, - IncomingPushMessage push, TextSecureGroup group, + TextSecureEnvelope envelope, TextSecureGroup group, GroupContext storage) { if (group.getAvatar().isPresent()) { @@ -168,7 +168,7 @@ public class GroupMessageProcessor { EncryptingSmsDatabase smsDatabase = DatabaseFactory.getEncryptingSmsDatabase(context); String body = Base64.encodeBytes(storage.toByteArray()); - IncomingTextMessage incoming = new IncomingTextMessage(push.getSource(), push.getSourceDevice(), push.getTimestampMillis(), body, Optional.of(group)); + IncomingTextMessage incoming = new IncomingTextMessage(envelope.getSource(), envelope.getSourceDevice(), envelope.getTimestamp(), body, Optional.of(group)); IncomingGroupMessage groupMessage = new IncomingGroupMessage(incoming, storage, body); Pair messageAndThreadId = smsDatabase.insertMessageInbox(masterSecret, groupMessage); diff --git a/src/org/thoughtcrime/securesms/jobs/PushDecryptJob.java b/src/org/thoughtcrime/securesms/jobs/PushDecryptJob.java index 68ff17faf4..ef7df5f4cf 100644 --- a/src/org/thoughtcrime/securesms/jobs/PushDecryptJob.java +++ b/src/org/thoughtcrime/securesms/jobs/PushDecryptJob.java @@ -5,8 +5,9 @@ import android.util.Log; import android.util.Pair; import org.thoughtcrime.securesms.ApplicationContext; -import org.thoughtcrime.securesms.crypto.SecurityEvent; import org.thoughtcrime.securesms.crypto.MasterSecret; +import org.thoughtcrime.securesms.crypto.SecurityEvent; +import org.thoughtcrime.securesms.crypto.storage.TextSecureAxolotlStore; import org.thoughtcrime.securesms.crypto.storage.TextSecureSessionStore; import org.thoughtcrime.securesms.database.DatabaseFactory; import org.thoughtcrime.securesms.database.EncryptingSmsDatabase; @@ -16,8 +17,8 @@ import org.thoughtcrime.securesms.groups.GroupMessageProcessor; import org.thoughtcrime.securesms.jobs.requirements.MasterSecretRequirement; import org.thoughtcrime.securesms.mms.IncomingMediaMessage; import org.thoughtcrime.securesms.notifications.MessageNotifier; -import org.thoughtcrime.securesms.push.TextSecureMessageReceiverFactory; import org.thoughtcrime.securesms.recipients.RecipientFactory; +import org.thoughtcrime.securesms.recipients.RecipientFormattingException; import org.thoughtcrime.securesms.recipients.Recipients; import org.thoughtcrime.securesms.service.KeyCachingService; import org.thoughtcrime.securesms.sms.IncomingEncryptedMessage; @@ -34,12 +35,13 @@ import org.whispersystems.libaxolotl.InvalidVersionException; import org.whispersystems.libaxolotl.LegacyMessageException; import org.whispersystems.libaxolotl.NoSessionException; import org.whispersystems.libaxolotl.UntrustedIdentityException; +import org.whispersystems.libaxolotl.state.AxolotlStore; import org.whispersystems.libaxolotl.state.SessionStore; import org.whispersystems.libaxolotl.util.guava.Optional; -import org.whispersystems.textsecure.api.TextSecureMessageReceiver; +import org.whispersystems.textsecure.api.messages.TextSecureEnvelope; import org.whispersystems.textsecure.api.messages.TextSecureGroup; import org.whispersystems.textsecure.api.messages.TextSecureMessage; -import org.whispersystems.textsecure.push.IncomingPushMessage; +import org.whispersystems.textsecure.crypto.TextSecureCipher; import org.whispersystems.textsecure.util.Base64; import ws.com.google.android.mms.MmsException; @@ -68,11 +70,11 @@ public class PushDecryptJob extends MasterSecretJob { @Override public void onRun() throws RequirementNotMetException { try { - MasterSecret masterSecret = getMasterSecret(); - PushDatabase database = DatabaseFactory.getPushDatabase(context); - IncomingPushMessage push = database.get(messageId); + MasterSecret masterSecret = getMasterSecret(); + PushDatabase database = DatabaseFactory.getPushDatabase(context); + TextSecureEnvelope envelope = database.get(messageId); - handleMessage(masterSecret, push); + handleMessage(masterSecret, envelope); database.delete(messageId); } catch (PushDatabase.NoSuchMessageException e) { @@ -91,42 +93,46 @@ public class PushDecryptJob extends MasterSecretJob { return false; } - private void handleMessage(MasterSecret masterSecret, IncomingPushMessage push) { + private void handleMessage(MasterSecret masterSecret, TextSecureEnvelope envelope) { try { - Recipients recipients = RecipientFactory.getRecipientsFromMessage(context, push, false); - long recipientId = recipients.getPrimaryRecipient().getRecipientId(); - TextSecureMessageReceiver messageReceiver = TextSecureMessageReceiverFactory.create(context, masterSecret); + Recipients recipients = RecipientFactory.getRecipientsFromString(context, envelope.getSource(), false); + long recipientId = recipients.getPrimaryRecipient().getRecipientId(); + int deviceId = envelope.getSourceDevice(); + AxolotlStore axolotlStore = new TextSecureAxolotlStore(context, masterSecret); + TextSecureCipher cipher = new TextSecureCipher(axolotlStore, recipientId, deviceId); - TextSecureMessage message = messageReceiver.receiveMessage(recipientId, push); + TextSecureMessage message = cipher.decrypt(envelope); - if (message.isEndSession()) handleEndSessionMessage(masterSecret, recipientId, push, message); - else if (message.isGroupUpdate()) handleGroupMessage(masterSecret, push, message); - else if (message.getAttachments().isPresent()) handleMediaMessage(masterSecret, push, message); - else handleTextMessage(masterSecret, push, message); + if (message.isEndSession()) handleEndSessionMessage(masterSecret, recipientId, envelope, message); + else if (message.isGroupUpdate()) handleGroupMessage(masterSecret, envelope, message); + else if (message.getAttachments().isPresent()) handleMediaMessage(masterSecret, envelope, message); + else handleTextMessage(masterSecret, envelope, message); } catch (InvalidVersionException e) { Log.w(TAG, e); - handleInvalidVersionMessage(masterSecret, push); - } catch (InvalidMessageException | InvalidKeyIdException | InvalidKeyException | MmsException e) { + handleInvalidVersionMessage(masterSecret, envelope); + } catch (InvalidMessageException | InvalidKeyIdException | InvalidKeyException | MmsException | RecipientFormattingException e) { Log.w(TAG, e); - handleCorruptMessage(masterSecret, push); + handleCorruptMessage(masterSecret, envelope); } catch (NoSessionException e) { Log.w(TAG, e); - handleNoSessionMessage(masterSecret, push); + handleNoSessionMessage(masterSecret, envelope); } catch (LegacyMessageException e) { Log.w(TAG, e); - handleLegacyMessage(masterSecret, push); + handleLegacyMessage(masterSecret, envelope); } catch (DuplicateMessageException e) { Log.w(TAG, e); - handleDuplicateMessage(masterSecret, push); + handleDuplicateMessage(masterSecret, envelope); } catch (UntrustedIdentityException e) { Log.w(TAG, e); - handleUntrustedIdentityMessage(masterSecret, push); + handleUntrustedIdentityMessage(masterSecret, envelope); } } - private void handleEndSessionMessage(MasterSecret masterSecret, long recipientId, IncomingPushMessage push, TextSecureMessage message) { - IncomingTextMessage incomingTextMessage = new IncomingTextMessage(push.getSource(), - push.getSourceDevice(), + private void handleEndSessionMessage(MasterSecret masterSecret, long recipientId, + TextSecureEnvelope envelope, TextSecureMessage message) + { + IncomingTextMessage incomingTextMessage = new IncomingTextMessage(envelope.getSource(), + envelope.getSourceDevice(), message.getTimestamp(), "", Optional.absent()); @@ -141,18 +147,18 @@ public class PushDecryptJob extends MasterSecretJob { MessageNotifier.updateNotification(context, masterSecret, messageAndThreadId.second); } - private void handleGroupMessage(MasterSecret masterSecret, IncomingPushMessage push, TextSecureMessage message) { - GroupMessageProcessor.process(context, masterSecret, push, message); + private void handleGroupMessage(MasterSecret masterSecret, TextSecureEnvelope envelope, TextSecureMessage message) { + GroupMessageProcessor.process(context, masterSecret, envelope, message); } - private void handleMediaMessage(MasterSecret masterSecret, IncomingPushMessage signal, TextSecureMessage message) + private void handleMediaMessage(MasterSecret masterSecret, TextSecureEnvelope envelope, TextSecureMessage message) throws MmsException { String localNumber = TextSecurePreferences.getLocalNumber(context); MmsDatabase database = DatabaseFactory.getMmsDatabase(context); - IncomingMediaMessage mediaMessage = new IncomingMediaMessage(masterSecret, signal.getSource(), + IncomingMediaMessage mediaMessage = new IncomingMediaMessage(masterSecret, envelope.getSource(), localNumber, message.getTimestamp(), - Optional.fromNullable(signal.getRelay()), + Optional.fromNullable(envelope.getRelay()), message.getBody(), message.getGroupInfo(), message.getAttachments()); @@ -172,11 +178,11 @@ public class PushDecryptJob extends MasterSecretJob { MessageNotifier.updateNotification(context, masterSecret, messageAndThreadId.second); } - private void handleTextMessage(MasterSecret masterSecret, IncomingPushMessage signal, TextSecureMessage message) { + private void handleTextMessage(MasterSecret masterSecret, TextSecureEnvelope envelope, TextSecureMessage message) { EncryptingSmsDatabase database = DatabaseFactory.getEncryptingSmsDatabase(context); String body = message.getBody().isPresent() ? message.getBody().get() : ""; - IncomingTextMessage textMessage = new IncomingTextMessage(signal.getSource(), - signal.getSourceDevice(), + IncomingTextMessage textMessage = new IncomingTextMessage(envelope.getSource(), + envelope.getSourceDevice(), message.getTimestamp(), body, message.getGroupInfo()); @@ -185,50 +191,48 @@ public class PushDecryptJob extends MasterSecretJob { } Pair messageAndThreadId = database.insertMessageInbox(masterSecret, textMessage); -// database.updateMessageBody(masterSecret, messageAndThreadId.first, body); - MessageNotifier.updateNotification(context, masterSecret, messageAndThreadId.second); } - private void handleInvalidVersionMessage(MasterSecret masterSecret, IncomingPushMessage push) { - Pair messageAndThreadId = insertPlaceholder(masterSecret, push); + private void handleInvalidVersionMessage(MasterSecret masterSecret, TextSecureEnvelope envelope) { + Pair messageAndThreadId = insertPlaceholder(masterSecret, envelope); DatabaseFactory.getEncryptingSmsDatabase(context).markAsInvalidVersionKeyExchange(messageAndThreadId.first); MessageNotifier.updateNotification(context, masterSecret, messageAndThreadId.second); } - private void handleCorruptMessage(MasterSecret masterSecret, IncomingPushMessage push) { - Pair messageAndThreadId = insertPlaceholder(masterSecret, push); + private void handleCorruptMessage(MasterSecret masterSecret, TextSecureEnvelope envelope) { + Pair messageAndThreadId = insertPlaceholder(masterSecret, envelope); DatabaseFactory.getEncryptingSmsDatabase(context).markAsDecryptFailed(messageAndThreadId.first); MessageNotifier.updateNotification(context, masterSecret, messageAndThreadId.second); } - private void handleNoSessionMessage(MasterSecret masterSecret, IncomingPushMessage push) { - Pair messageAndThreadId = insertPlaceholder(masterSecret, push); + private void handleNoSessionMessage(MasterSecret masterSecret, TextSecureEnvelope envelope) { + Pair messageAndThreadId = insertPlaceholder(masterSecret, envelope); DatabaseFactory.getEncryptingSmsDatabase(context).markAsNoSession(messageAndThreadId.first); MessageNotifier.updateNotification(context, masterSecret, messageAndThreadId.second); } - private void handleLegacyMessage(MasterSecret masterSecret, IncomingPushMessage push) { - Pair messageAndThreadId = insertPlaceholder(masterSecret, push); + private void handleLegacyMessage(MasterSecret masterSecret, TextSecureEnvelope envelope) { + Pair messageAndThreadId = insertPlaceholder(masterSecret, envelope); DatabaseFactory.getEncryptingSmsDatabase(context).markAsLegacyVersion(messageAndThreadId.first); MessageNotifier.updateNotification(context, masterSecret, messageAndThreadId.second); } - private void handleDuplicateMessage(MasterSecret masterSecret, IncomingPushMessage push) { - Pair messageAndThreadId = insertPlaceholder(masterSecret, push); + private void handleDuplicateMessage(MasterSecret masterSecret, TextSecureEnvelope envelope) { + Pair messageAndThreadId = insertPlaceholder(masterSecret, envelope); DatabaseFactory.getEncryptingSmsDatabase(context).markAsDecryptDuplicate(messageAndThreadId.first); MessageNotifier.updateNotification(context, masterSecret, messageAndThreadId.second); } - private void handleUntrustedIdentityMessage(MasterSecret masterSecret, IncomingPushMessage push) { - String encoded = Base64.encodeBytes(push.getBody()); - IncomingTextMessage textMessage = new IncomingTextMessage(push.getSource(), push.getSourceDevice(), - push.getTimestampMillis(), encoded, + private void handleUntrustedIdentityMessage(MasterSecret masterSecret, TextSecureEnvelope envelope) { + String encoded = Base64.encodeBytes(envelope.getMessage()); + IncomingTextMessage textMessage = new IncomingTextMessage(envelope.getSource(), envelope.getSourceDevice(), + envelope.getTimestamp(), encoded, Optional.absent()); IncomingPreKeyBundleMessage bundleMessage = new IncomingPreKeyBundleMessage(textMessage, encoded); @@ -238,11 +242,11 @@ public class PushDecryptJob extends MasterSecretJob { MessageNotifier.updateNotification(context, masterSecret, messageAndThreadId.second); } - private Pair insertPlaceholder(MasterSecret masterSecret, IncomingPushMessage push) { + private Pair insertPlaceholder(MasterSecret masterSecret, TextSecureEnvelope envelope) { EncryptingSmsDatabase database = DatabaseFactory.getEncryptingSmsDatabase(context); - IncomingTextMessage textMessage = new IncomingTextMessage(push.getSource(), push.getSourceDevice(), - push.getTimestampMillis(), "", + IncomingTextMessage textMessage = new IncomingTextMessage(envelope.getSource(), envelope.getSourceDevice(), + envelope.getTimestamp(), "", Optional.absent()); textMessage = new IncomingEncryptedMessage(textMessage, ""); diff --git a/src/org/thoughtcrime/securesms/jobs/PushReceiveJob.java b/src/org/thoughtcrime/securesms/jobs/PushReceiveJob.java index 2a006e7be3..cc8d7d715b 100644 --- a/src/org/thoughtcrime/securesms/jobs/PushReceiveJob.java +++ b/src/org/thoughtcrime/securesms/jobs/PushReceiveJob.java @@ -9,11 +9,10 @@ import org.thoughtcrime.securesms.util.TextSecurePreferences; import org.whispersystems.jobqueue.JobManager; import org.whispersystems.jobqueue.JobParameters; import org.whispersystems.libaxolotl.InvalidVersionException; +import org.whispersystems.textsecure.api.messages.TextSecureEnvelope; import org.whispersystems.textsecure.directory.Directory; import org.whispersystems.textsecure.directory.NotInDirectoryException; import org.whispersystems.textsecure.push.ContactTokenDetails; -import org.whispersystems.textsecure.push.IncomingEncryptedPushMessage; -import org.whispersystems.textsecure.push.IncomingPushMessage; import java.io.IOException; @@ -37,20 +36,19 @@ public class PushReceiveJob extends ContextJob { @Override public void onRun() { try { - String sessionKey = TextSecurePreferences.getSignalingKey(context); - IncomingEncryptedPushMessage encrypted = new IncomingEncryptedPushMessage(data, sessionKey); - IncomingPushMessage message = encrypted.getIncomingPushMessage(); + String sessionKey = TextSecurePreferences.getSignalingKey(context); + TextSecureEnvelope envelope = new TextSecureEnvelope(data, sessionKey); - if (!isActiveNumber(context, message.getSource())) { + if (!isActiveNumber(context, envelope.getSource())) { Directory directory = Directory.getInstance(context); ContactTokenDetails contactTokenDetails = new ContactTokenDetails(); - contactTokenDetails.setNumber(message.getSource()); + contactTokenDetails.setNumber(envelope.getSource()); directory.setNumber(contactTokenDetails, true); } - if (message.isReceipt()) handleReceipt(message); - else handleMessage(message); + if (envelope.isReceipt()) handleReceipt(envelope); + else handleMessage(envelope); } catch (IOException | InvalidVersionException e) { Log.w(TAG, e); } @@ -66,21 +64,21 @@ public class PushReceiveJob extends ContextJob { return false; } - private void handleMessage(IncomingPushMessage message) { + private void handleMessage(TextSecureEnvelope envelope) { JobManager jobManager = ApplicationContext.getInstance(context).getJobManager(); - long messageId = DatabaseFactory.getPushDatabase(context).insert(message); + long messageId = DatabaseFactory.getPushDatabase(context).insert(envelope); - jobManager.add(new DeliveryReceiptJob(context, message.getSource(), - message.getTimestampMillis(), - message.getRelay())); + jobManager.add(new DeliveryReceiptJob(context, envelope.getSource(), + envelope.getTimestamp(), + envelope.getRelay())); jobManager.add(new PushDecryptJob(context, messageId)); } - private void handleReceipt(IncomingPushMessage message) { - Log.w(TAG, String.format("Received receipt: (XXXXX, %d)", message.getTimestampMillis())); - DatabaseFactory.getMmsSmsDatabase(context).incrementDeliveryReceiptCount(message.getSource(), - message.getTimestampMillis()); + private void handleReceipt(TextSecureEnvelope envelope) { + Log.w(TAG, String.format("Received receipt: (XXXXX, %d)", envelope.getTimestamp())); + DatabaseFactory.getMmsSmsDatabase(context).incrementDeliveryReceiptCount(envelope.getSource(), + envelope.getTimestamp()); } private boolean isActiveNumber(Context context, String e164number) { diff --git a/src/org/thoughtcrime/securesms/mms/IncomingMediaMessage.java b/src/org/thoughtcrime/securesms/mms/IncomingMediaMessage.java index 2896c1bf21..f9ee166b7c 100644 --- a/src/org/thoughtcrime/securesms/mms/IncomingMediaMessage.java +++ b/src/org/thoughtcrime/securesms/mms/IncomingMediaMessage.java @@ -1,14 +1,12 @@ package org.thoughtcrime.securesms.mms; -import org.thoughtcrime.securesms.util.GroupUtil; -import org.thoughtcrime.securesms.util.Util; import org.thoughtcrime.securesms.crypto.MasterCipher; import org.thoughtcrime.securesms.crypto.MasterSecret; +import org.thoughtcrime.securesms.util.GroupUtil; +import org.thoughtcrime.securesms.util.Util; import org.whispersystems.libaxolotl.util.guava.Optional; import org.whispersystems.textsecure.api.messages.TextSecureAttachment; import org.whispersystems.textsecure.api.messages.TextSecureGroup; -import org.whispersystems.textsecure.push.IncomingPushMessage; -import org.whispersystems.textsecure.push.PushMessageProtos.PushMessageContent; import org.whispersystems.textsecure.util.Base64; import java.util.List; diff --git a/src/org/thoughtcrime/securesms/notifications/MessageNotifier.java b/src/org/thoughtcrime/securesms/notifications/MessageNotifier.java index aef3c411bc..3f390f381c 100644 --- a/src/org/thoughtcrime/securesms/notifications/MessageNotifier.java +++ b/src/org/thoughtcrime/securesms/notifications/MessageNotifier.java @@ -39,17 +39,17 @@ import android.util.Log; import org.thoughtcrime.securesms.R; import org.thoughtcrime.securesms.RoutingActivity; -import org.thoughtcrime.securesms.database.PushDatabase; -import org.thoughtcrime.securesms.recipients.RecipientFactory; -import org.thoughtcrime.securesms.recipients.RecipientFormattingException; import org.thoughtcrime.securesms.crypto.MasterSecret; import org.thoughtcrime.securesms.database.DatabaseFactory; import org.thoughtcrime.securesms.database.MmsSmsDatabase; +import org.thoughtcrime.securesms.database.PushDatabase; import org.thoughtcrime.securesms.database.model.MessageRecord; import org.thoughtcrime.securesms.recipients.Recipient; +import org.thoughtcrime.securesms.recipients.RecipientFactory; +import org.thoughtcrime.securesms.recipients.RecipientFormattingException; import org.thoughtcrime.securesms.recipients.Recipients; import org.thoughtcrime.securesms.util.TextSecurePreferences; -import org.whispersystems.textsecure.push.IncomingPushMessage; +import org.whispersystems.textsecure.api.messages.TextSecureEnvelope; import java.io.IOException; import java.util.List; @@ -285,24 +285,24 @@ public class MessageNotifier { if (masterSecret != null) return; PushDatabase.Reader reader = null; - IncomingPushMessage message; + TextSecureEnvelope envelope; try { reader = DatabaseFactory.getPushDatabase(context).readerFor(cursor); - while ((message = reader.getNext()) != null) { - Recipient recipient; + while ((envelope = reader.getNext()) != null) { + Recipients recipients; try { - recipient = RecipientFactory.getRecipientsFromString(context, message.getSource(), false).getPrimaryRecipient(); + recipients = RecipientFactory.getRecipientsFromString(context, envelope.getSource(), false); } catch (RecipientFormattingException e) { Log.w("MessageNotifier", e); - recipient = Recipient.getUnknownRecipient(context); + recipients = new Recipients(Recipient.getUnknownRecipient(context)); } - Recipients recipients = RecipientFactory.getRecipientsFromMessage(context, message, false); - long threadId = DatabaseFactory.getThreadDatabase(context).getThreadIdFor(recipients); - SpannableString body = new SpannableString(context.getString(R.string.MessageNotifier_encrypted_message)); + Recipient recipient = recipients.getPrimaryRecipient(); + long threadId = DatabaseFactory.getThreadDatabase(context).getThreadIdFor(recipients); + SpannableString body = new SpannableString(context.getString(R.string.MessageNotifier_encrypted_message)); body.setSpan(new StyleSpan(android.graphics.Typeface.ITALIC), 0, body.length(), Spannable.SPAN_EXCLUSIVE_EXCLUSIVE); notificationState.addNotification(new NotificationItem(recipient, recipients, null, threadId, body, null)); diff --git a/src/org/thoughtcrime/securesms/recipients/RecipientFactory.java b/src/org/thoughtcrime/securesms/recipients/RecipientFactory.java index c577e11860..b9edbef024 100644 --- a/src/org/thoughtcrime/securesms/recipients/RecipientFactory.java +++ b/src/org/thoughtcrime/securesms/recipients/RecipientFactory.java @@ -21,7 +21,6 @@ import android.util.Log; import org.thoughtcrime.securesms.contacts.ContactPhotoFactory; import org.thoughtcrime.securesms.database.CanonicalAddressDatabase; -import org.whispersystems.textsecure.push.IncomingPushMessage; import org.whispersystems.textsecure.util.Util; import java.util.LinkedList; @@ -73,18 +72,6 @@ public class RecipientFactory { return new Recipients(results); } - public static Recipients getRecipientsFromMessage(Context context, - IncomingPushMessage message, - boolean asynchronous) - { - try { - return getRecipientsFromString(context, message.getSource(), asynchronous); - } catch (RecipientFormattingException e) { - Log.w("RecipientFactory", e); - return new Recipients(Recipient.getUnknownRecipient(context)); - } - } - private static Recipient getRecipientFromProviderId(Context context, String recipientId, boolean asynchronous) { try { return provider.getRecipient(context, Long.parseLong(recipientId), asynchronous); diff --git a/src/org/thoughtcrime/securesms/service/MmsSender.java b/src/org/thoughtcrime/securesms/service/MmsSender.java index 512220b997..ffad1f380a 100644 --- a/src/org/thoughtcrime/securesms/service/MmsSender.java +++ b/src/org/thoughtcrime/securesms/service/MmsSender.java @@ -76,7 +76,7 @@ public class MmsSender { try { Log.w("MmsSender", "Passing to MMS transport: " + message.getDatabaseMessageId()); database.markAsSending(message.getDatabaseMessageId()); - MmsSendResult result = transport.deliver(message, threadId); + MmsSendResult result = transport.deliver(message); if (result.isUpgradedSecure()) database.markAsSecure(message.getDatabaseMessageId()); if (result.isPush()) database.markAsPush(message.getDatabaseMessageId()); diff --git a/src/org/thoughtcrime/securesms/sms/IncomingTextMessage.java b/src/org/thoughtcrime/securesms/sms/IncomingTextMessage.java index 85a257041d..4dea924f38 100644 --- a/src/org/thoughtcrime/securesms/sms/IncomingTextMessage.java +++ b/src/org/thoughtcrime/securesms/sms/IncomingTextMessage.java @@ -7,13 +7,10 @@ import android.telephony.SmsMessage; import org.thoughtcrime.securesms.util.GroupUtil; import org.whispersystems.libaxolotl.util.guava.Optional; import org.whispersystems.textsecure.api.messages.TextSecureGroup; -import org.whispersystems.textsecure.push.IncomingPushMessage; import org.whispersystems.textsecure.storage.RecipientDevice; import java.util.List; -import static org.whispersystems.textsecure.push.PushMessageProtos.PushMessageContent.GroupContext; - public class IncomingTextMessage implements Parcelable { public static final Parcelable.Creator CREATOR = new Parcelable.Creator() { diff --git a/src/org/thoughtcrime/securesms/transport/PushTransport.java b/src/org/thoughtcrime/securesms/transport/PushTransport.java index 73be368e53..c246be9e6c 100644 --- a/src/org/thoughtcrime/securesms/transport/PushTransport.java +++ b/src/org/thoughtcrime/securesms/transport/PushTransport.java @@ -89,7 +89,7 @@ public class PushTransport extends BaseTransport { } } - public void deliverGroupMessage(SendReq message, long threadId) + public void deliverGroupMessage(SendReq message) throws IOException, RecipientFormattingException, InvalidNumberException, EncapsulatedExceptions { TextSecureMessageSender messageSender = TextSecureMessageSenderFactory.create(context, masterSecret); @@ -121,7 +121,7 @@ public class PushTransport extends BaseTransport { } } - public void deliver(SendReq message, long threadId) + public void deliver(SendReq message) throws IOException, RecipientFormattingException, InvalidNumberException, EncapsulatedExceptions { TextSecureMessageSender messageSender = TextSecureMessageSenderFactory.create(context, masterSecret); @@ -131,7 +131,7 @@ public class PushTransport extends BaseTransport { List unregisteredUsers = new LinkedList<>(); if (GroupUtil.isEncodedGroup(destination)) { - deliverGroupMessage(message, threadId); + deliverGroupMessage(message); return; } @@ -182,6 +182,7 @@ public class PushTransport extends BaseTransport { ContentType.isVideoType(contentType)) { byte[] data = message.getBody().getPart(i).getData(); + Log.w(TAG, "Adding attachment..."); attachments.add(new TextSecureAttachmentStream(new ByteArrayInputStream(data), contentType, data.length)); } } diff --git a/src/org/thoughtcrime/securesms/transport/UniversalTransport.java b/src/org/thoughtcrime/securesms/transport/UniversalTransport.java index d649408d02..aeaa144813 100644 --- a/src/org/thoughtcrime/securesms/transport/UniversalTransport.java +++ b/src/org/thoughtcrime/securesms/transport/UniversalTransport.java @@ -111,7 +111,7 @@ public class UniversalTransport { } } - public MmsSendResult deliver(SendReq mediaMessage, long threadId) + public MmsSendResult deliver(SendReq mediaMessage) throws UndeliverableMessageException, RetryLaterException, UntrustedIdentityException, SecureFallbackApprovalException, InsecureFallbackApprovalException { @@ -124,7 +124,7 @@ public class UniversalTransport { } if (GroupUtil.isEncodedGroup(mediaMessage.getTo()[0].getString())) { - return deliverGroupMessage(mediaMessage, threadId); + return deliverGroupMessage(mediaMessage); } if (!TextSecurePreferences.isPushRegistered(context)) { @@ -143,7 +143,7 @@ public class UniversalTransport { try { Log.w(TAG, "Using GCM as transport..."); - pushTransport.deliver(mediaMessage, threadId); + pushTransport.deliver(mediaMessage); return new MmsSendResult("push".getBytes("UTF-8"), 0, true, true); } catch (IOException ioe) { Log.w(TAG, ioe); @@ -216,7 +216,7 @@ public class UniversalTransport { } } - private MmsSendResult deliverGroupMessage(SendReq mediaMessage, long threadId) + private MmsSendResult deliverGroupMessage(SendReq mediaMessage) throws RetryLaterException, UndeliverableMessageException { if (!TextSecurePreferences.isPushRegistered(context)) { @@ -224,7 +224,7 @@ public class UniversalTransport { } try { - pushTransport.deliver(mediaMessage, threadId); + pushTransport.deliver(mediaMessage); return new MmsSendResult("push".getBytes("UTF-8"), 0, true, true); } catch (IOException e) { Log.w(TAG, e);