Move API around.

This commit is contained in:
Moxie Marlinspike 2014-11-04 15:01:32 -08:00
parent a3f1d9cdfd
commit 99f42e2ee1
17 changed files with 303 additions and 458 deletions

View File

@ -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<TextSecureAttachment> 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<String> 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());
}
}

View File

@ -173,11 +173,13 @@ public class TextSecureMessageSender {
List<AttachmentPointer> 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();

View File

@ -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() {

View File

@ -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);
}
}

View File

@ -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<TextSecureAttachment> 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<String> 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());
}
}

View File

@ -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 <http://www.gnu.org/licenses/>.
*/
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<IncomingPushMessage> CREATOR = new Parcelable.Creator<IncomingPushMessage>() {
@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;
}
}

View File

@ -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();
}

View File

@ -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<Long, Long> messageAndThreadId = smsDatabase.insertMessageInbox(masterSecret, groupMessage);

View File

@ -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.<TextSecureGroup>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<Long, Long> 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<Long, Long> messageAndThreadId = insertPlaceholder(masterSecret, push);
private void handleInvalidVersionMessage(MasterSecret masterSecret, TextSecureEnvelope envelope) {
Pair<Long, Long> messageAndThreadId = insertPlaceholder(masterSecret, envelope);
DatabaseFactory.getEncryptingSmsDatabase(context).markAsInvalidVersionKeyExchange(messageAndThreadId.first);
MessageNotifier.updateNotification(context, masterSecret, messageAndThreadId.second);
}
private void handleCorruptMessage(MasterSecret masterSecret, IncomingPushMessage push) {
Pair<Long, Long> messageAndThreadId = insertPlaceholder(masterSecret, push);
private void handleCorruptMessage(MasterSecret masterSecret, TextSecureEnvelope envelope) {
Pair<Long, Long> messageAndThreadId = insertPlaceholder(masterSecret, envelope);
DatabaseFactory.getEncryptingSmsDatabase(context).markAsDecryptFailed(messageAndThreadId.first);
MessageNotifier.updateNotification(context, masterSecret, messageAndThreadId.second);
}
private void handleNoSessionMessage(MasterSecret masterSecret, IncomingPushMessage push) {
Pair<Long, Long> messageAndThreadId = insertPlaceholder(masterSecret, push);
private void handleNoSessionMessage(MasterSecret masterSecret, TextSecureEnvelope envelope) {
Pair<Long, Long> messageAndThreadId = insertPlaceholder(masterSecret, envelope);
DatabaseFactory.getEncryptingSmsDatabase(context).markAsNoSession(messageAndThreadId.first);
MessageNotifier.updateNotification(context, masterSecret, messageAndThreadId.second);
}
private void handleLegacyMessage(MasterSecret masterSecret, IncomingPushMessage push) {
Pair<Long, Long> messageAndThreadId = insertPlaceholder(masterSecret, push);
private void handleLegacyMessage(MasterSecret masterSecret, TextSecureEnvelope envelope) {
Pair<Long, Long> messageAndThreadId = insertPlaceholder(masterSecret, envelope);
DatabaseFactory.getEncryptingSmsDatabase(context).markAsLegacyVersion(messageAndThreadId.first);
MessageNotifier.updateNotification(context, masterSecret, messageAndThreadId.second);
}
private void handleDuplicateMessage(MasterSecret masterSecret, IncomingPushMessage push) {
Pair<Long, Long> messageAndThreadId = insertPlaceholder(masterSecret, push);
private void handleDuplicateMessage(MasterSecret masterSecret, TextSecureEnvelope envelope) {
Pair<Long, Long> 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.<TextSecureGroup>absent());
IncomingPreKeyBundleMessage bundleMessage = new IncomingPreKeyBundleMessage(textMessage, encoded);
@ -238,11 +242,11 @@ public class PushDecryptJob extends MasterSecretJob {
MessageNotifier.updateNotification(context, masterSecret, messageAndThreadId.second);
}
private Pair<Long, Long> insertPlaceholder(MasterSecret masterSecret, IncomingPushMessage push) {
private Pair<Long, Long> 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.<TextSecureGroup>absent());
textMessage = new IncomingEncryptedMessage(textMessage, "");

View File

@ -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) {

View File

@ -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;

View File

@ -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));

View File

@ -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);

View File

@ -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());

View File

@ -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<IncomingTextMessage> CREATOR = new Parcelable.Creator<IncomingTextMessage>() {

View File

@ -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<UnregisteredUserException> 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));
}
}

View File

@ -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);