Locally encrypted messages no longer show as ciphertext notifications.

This commit is contained in:
Moxie Marlinspike 2013-04-30 11:14:01 -07:00
parent 7c47ea5cec
commit e80882b83b
14 changed files with 130 additions and 109 deletions

View File

@ -195,7 +195,7 @@ public class ConversationItem extends LinearLayout {
if (!messageRecord.isOutgoing() && messageRecord.getRecipients().isSingleRecipient()) {
checkForAutoInitiate(messageRecord.getIndividualRecipient(),
messageRecord.getBody(),
messageRecord.getBody().getBody(),
messageRecord.getThreadId());
}
}
@ -321,7 +321,7 @@ public class ConversationItem extends LinearLayout {
private void handleKeyExchangeClicked() {
Intent intent = new Intent(context, ReceiveKeyActivity.class);
intent.putExtra("recipient", messageRecord.getIndividualRecipient());
intent.putExtra("body", messageRecord.getBody());
intent.putExtra("body", messageRecord.getBody().getBody());
intent.putExtra("thread_id", messageRecord.getThreadId());
intent.putExtra("master_secret", masterSecret);
intent.putExtra("sent", messageRecord.isOutgoing());

View File

@ -122,7 +122,7 @@ public class DecryptingQueue {
SmsMessageRecord record)
{
long messageId = record.getId();
String body = record.getBody();
String body = record.getBody().getBody();
String originator = record.getIndividualRecipient().getNumber();
boolean isSecureMessage = record.isSecure();

View File

@ -26,6 +26,7 @@ import org.thoughtcrime.securesms.crypto.AsymmetricMasterCipher;
import org.thoughtcrime.securesms.crypto.AsymmetricMasterSecret;
import org.thoughtcrime.securesms.crypto.MasterCipher;
import org.thoughtcrime.securesms.crypto.MasterSecret;
import org.thoughtcrime.securesms.database.model.DisplayRecord;
import org.thoughtcrime.securesms.sms.IncomingTextMessage;
import org.thoughtcrime.securesms.sms.OutgoingTextMessage;
import org.thoughtcrime.securesms.util.InvalidMessageException;
@ -128,27 +129,27 @@ public class EncryptingSmsDatabase extends SmsDatabase {
}
@Override
protected String getBody(Cursor cursor) {
protected DisplayRecord.Body getBody(Cursor cursor) {
long type = cursor.getLong(cursor.getColumnIndexOrThrow(SmsDatabase.TYPE));
String ciphertext = super.getBody(cursor);
String ciphertext = cursor.getString(cursor.getColumnIndexOrThrow(SmsDatabase.BODY));
try {
if (SmsDatabase.Types.isSymmetricEncryption(type)) {
String plaintext = plaintextCache.get(ciphertext);
if (plaintext != null)
return plaintext;
return new DisplayRecord.Body(plaintext, true);
plaintext = masterCipher.decryptBody(ciphertext);
plaintextCache.put(ciphertext, plaintext);
return plaintext;
return new DisplayRecord.Body(plaintext, true);
} else {
return ciphertext;
return new DisplayRecord.Body(ciphertext, true);
}
} catch (InvalidMessageException e) {
Log.w("EncryptingSmsDatabase", e);
return "Error decrypting message.";
return new DisplayRecord.Body("Error decrypting message.", true);
}
}
}

View File

@ -29,6 +29,7 @@ import org.thoughtcrime.securesms.R;
import org.thoughtcrime.securesms.contacts.ContactPhotoFactory;
import org.thoughtcrime.securesms.crypto.MasterCipher;
import org.thoughtcrime.securesms.crypto.MasterSecret;
import org.thoughtcrime.securesms.database.model.DisplayRecord;
import org.thoughtcrime.securesms.database.model.MediaMmsMessageRecord;
import org.thoughtcrime.securesms.database.model.MessageRecord;
import org.thoughtcrime.securesms.database.model.NotificationMmsMessageRecord;
@ -241,14 +242,14 @@ public class MmsDatabase extends Database implements MmsSmsColumns {
ContentValues contentValues = new ContentValues();
contentValues.put(RESPONSE_STATUS, status);
database.update(TABLE_NAME, contentValues, ID_WHERE, new String[] {messageId+""});
database.update(TABLE_NAME, contentValues, ID_WHERE, new String[] {messageId + ""});
}
private void updateMailboxBitmask(long id, long maskOff, long maskOn) {
SQLiteDatabase db = databaseHelper.getWritableDatabase();
db.execSQL("UPDATE " + TABLE_NAME +
" SET " + MESSAGE_BOX + " = (" + MESSAGE_BOX + " & " + (Types.TOTAL_MASK - maskOff) + " | " + maskOn + " )" +
" WHERE " + ID + " = ?", new String[] {id+""});
" WHERE " + ID + " = ?", new String[] {id + ""});
}
public void markAsSentFailed(long messageId) {
@ -272,7 +273,7 @@ public class MmsDatabase extends Database implements MmsSmsColumns {
ContentValues contentValues = new ContentValues();
contentValues.put(STATUS, state);
database.update(TABLE_NAME, contentValues, ID_WHERE, new String[] {messageId+""});
database.update(TABLE_NAME, contentValues, ID_WHERE, new String[] {messageId + ""});
notifyConversationListeners(getThreadIdForMessage(messageId));
}
@ -764,7 +765,7 @@ public class MmsDatabase extends Database implements MmsSmsColumns {
long dateReceived = cursor.getLong(cursor.getColumnIndexOrThrow(MmsDatabase.NORMALIZED_DATE_RECEIVED));
long box = cursor.getLong(cursor.getColumnIndexOrThrow(MmsDatabase.MESSAGE_BOX));
long threadId = cursor.getLong(cursor.getColumnIndexOrThrow(MmsDatabase.THREAD_ID));
String body = getBody(cursor);
DisplayRecord.Body body = getBody(cursor);
int partCount = cursor.getInt(cursor.getColumnIndexOrThrow(MmsDatabase.PART_COUNT));
Recipient recipient = getMessageRecipient(id);
@ -775,19 +776,21 @@ public class MmsDatabase extends Database implements MmsSmsColumns {
slideDeck, partCount, box);
}
private String getBody(Cursor cursor) {
private DisplayRecord.Body getBody(Cursor cursor) {
try {
String body = cursor.getString(cursor.getColumnIndexOrThrow(MmsDatabase.BODY));
long box = cursor.getLong(cursor.getColumnIndexOrThrow(MmsDatabase.MESSAGE_BOX));
if (body != null && masterCipher != null && Types.isSymmetricEncryption(box)) {
return masterCipher.decryptBody(body);
if (!Util.isEmpty(body) && masterCipher != null && Types.isSymmetricEncryption(box)) {
return new DisplayRecord.Body(masterCipher.decryptBody(body), true);
} else if (!Util.isEmpty(body) && masterCipher == null && Types.isSymmetricEncryption(box)) {
return new DisplayRecord.Body(body, false);
} else {
return new DisplayRecord.Body(body == null ? "" : body, true);
}
return body;
} catch (InvalidMessageException e) {
Log.w("MmsDatabase", e);
return "Error decrypting message.";
return new DisplayRecord.Body("Error decrypting message.", true);
}
}

View File

@ -27,6 +27,7 @@ import android.util.Log;
import android.util.Pair;
import org.thoughtcrime.securesms.contacts.ContactPhotoFactory;
import org.thoughtcrime.securesms.database.model.DisplayRecord;
import org.thoughtcrime.securesms.database.model.SmsMessageRecord;
import org.thoughtcrime.securesms.recipients.Recipient;
import org.thoughtcrime.securesms.recipients.RecipientFactory;
@ -179,7 +180,7 @@ public class SmsDatabase extends Database implements MmsSmsColumns {
database.update(TABLE_NAME, contentValues, THREAD_ID + " = ? AND " + READ + " = 0", new String[] {threadId+""});
long end = System.currentTimeMillis();
Log.w("SmsDatabase", "setMessagesRead time: " + (end-start));
Log.w("SmsDatabase", "setMessagesRead time: " + (end - start));
}
protected void updateMessageBodyAndType(long messageId, String body, long maskOff, long maskOn) {
@ -403,7 +404,7 @@ public class SmsDatabase extends Database implements MmsSmsColumns {
long threadId = cursor.getLong(cursor.getColumnIndexOrThrow(SmsDatabase.THREAD_ID));
int status = cursor.getInt(cursor.getColumnIndexOrThrow(SmsDatabase.STATUS));
Recipients recipients = getRecipientsFor(address);
String body = getBody(cursor);
DisplayRecord.Body body = getBody(cursor);
return new SmsMessageRecord(context, messageId, body, recipients,
recipients.getPrimaryRecipient(),
@ -421,8 +422,15 @@ public class SmsDatabase extends Database implements MmsSmsColumns {
}
}
protected String getBody(Cursor cursor) {
return cursor.getString(cursor.getColumnIndexOrThrow(SmsDatabase.BODY));
protected DisplayRecord.Body getBody(Cursor cursor) {
long type = cursor.getLong(cursor.getColumnIndexOrThrow(SmsDatabase.TYPE));
String body = cursor.getString(cursor.getColumnIndexOrThrow(SmsDatabase.BODY));
if (Types.isSymmetricEncryption(type)) {
return new DisplayRecord.Body(body, false);
} else {
return new DisplayRecord.Body(body, true);
}
}
public void close() {

View File

@ -25,6 +25,7 @@ import android.util.Log;
import org.thoughtcrime.securesms.crypto.MasterCipher;
import org.thoughtcrime.securesms.crypto.MasterSecret;
import org.thoughtcrime.securesms.database.model.DisplayRecord;
import org.thoughtcrime.securesms.database.model.MessageRecord;
import org.thoughtcrime.securesms.database.model.ThreadRecord;
import org.thoughtcrime.securesms.recipients.Recipient;
@ -372,7 +373,7 @@ public class ThreadDatabase extends Database {
MessageRecord record = null;
if (reader != null && (record = reader.getNext()) != null) {
updateThread(threadId, count, record.getBody(), record.getDateReceived(), record.getType());
updateThread(threadId, count, record.getBody().getBody(), record.getDateReceived(), record.getType());
} else {
deleteThread(threadId);
}
@ -401,13 +402,13 @@ public class ThreadDatabase extends Database {
public class Reader {
private final Cursor cursor;
private final MasterSecret masterSecret;
private final MasterCipher masterCipher;
public Reader(Cursor cursor, MasterSecret masterSecret) {
this.cursor = cursor;
this.masterSecret = masterSecret;
this.masterCipher = new MasterCipher(masterSecret);
if (masterSecret != null) this.masterCipher = new MasterCipher(masterSecret);
else this.masterCipher = null;
}
public ThreadRecord getNext() {
@ -422,7 +423,7 @@ public class ThreadDatabase extends Database {
String recipientId = cursor.getString(cursor.getColumnIndexOrThrow(ThreadDatabase.RECIPIENT_IDS));
Recipients recipients = RecipientFactory.getRecipientsForIds(context, recipientId, true);
String body = getPlaintextBody(cursor);
DisplayRecord.Body body = getPlaintextBody(cursor);
long date = cursor.getLong(cursor.getColumnIndexOrThrow(ThreadDatabase.DATE));
long count = cursor.getLong(cursor.getColumnIndexOrThrow(ThreadDatabase.MESSAGE_COUNT));
long read = cursor.getLong(cursor.getColumnIndexOrThrow(ThreadDatabase.READ));
@ -433,29 +434,24 @@ public class ThreadDatabase extends Database {
read == 1, threadId, type, distributionType);
}
private String getPlaintextBody(Cursor cursor) {
long type = cursor.getLong(cursor.getColumnIndexOrThrow(ThreadDatabase.SNIPPET_TYPE));
String ciphertextBody = cursor.getString(cursor.getColumnIndexOrThrow(SNIPPET));
if (masterSecret == null)
return ciphertextBody;
private DisplayRecord.Body getPlaintextBody(Cursor cursor) {
try {
if (!Util.isEmpty(ciphertextBody) && MmsSmsColumns.Types.isSymmetricEncryption(type)) {
return masterCipher.decryptBody(ciphertextBody);
long type = cursor.getLong(cursor.getColumnIndexOrThrow(ThreadDatabase.SNIPPET_TYPE));
String body = cursor.getString(cursor.getColumnIndexOrThrow(SNIPPET));
if (!Util.isEmpty(body) && masterCipher != null && MmsSmsColumns.Types.isSymmetricEncryption(type)) {
return new DisplayRecord.Body(masterCipher.decryptBody(body), true);
} else if (!Util.isEmpty(body) && masterCipher == null && MmsSmsColumns.Types.isSymmetricEncryption(type)) {
return new DisplayRecord.Body(body, false);
} else {
return ciphertextBody;
return new DisplayRecord.Body(body, true);
}
} catch (InvalidMessageException e) {
Log.w("ThreadDatabase", e);
return "Error decrypting message.";
return new DisplayRecord.Body("Error decrypting message.", true);
}
}
protected String getBody(Cursor cursor) {
return cursor.getString(cursor.getColumnIndexOrThrow(SmsDatabase.BODY));
}
public void close() {
cursor.close();
}

View File

@ -33,15 +33,16 @@ import org.thoughtcrime.securesms.recipients.Recipients;
public abstract class DisplayRecord {
protected final Context context;
protected final long type;
private final Recipients recipients;
private final long dateSent;
private final long dateReceived;
private final long threadId;
protected final long type;
private final Body body;
// private final String body;
private final String body;
public DisplayRecord(Context context, String body, Recipients recipients, long dateSent,
public DisplayRecord(Context context, Body body, Recipients recipients, long dateSent,
long dateReceived, long threadId, long type)
{
this.context = context.getApplicationContext();
@ -53,8 +54,9 @@ public abstract class DisplayRecord {
this.body = body;
}
public String getBody() {
return body == null ? "" : body;
public Body getBody() {
return body;
// return body == null ? "" : body;
}
public abstract SpannableString getDisplayBody();
@ -78,4 +80,22 @@ public abstract class DisplayRecord {
public boolean isKeyExchange() {
return SmsDatabase.Types.isKeyExchangeType(type);
}
public static class Body {
private final String body;
private final boolean plaintext;
public Body(String body, boolean plaintext) {
this.body = body;
this.plaintext = plaintext;
}
public boolean isPlaintext() {
return plaintext;
}
public String getBody() {
return body == null ? "" : body;
}
}
}

View File

@ -43,7 +43,7 @@ public class MediaMmsMessageRecord extends MessageRecord {
public MediaMmsMessageRecord(Context context, long id, Recipients recipients,
Recipient individualRecipient, long dateSent, long dateReceived,
long threadId, String body, ListenableFutureTask<SlideDeck> slideDeck,
long threadId, Body body, ListenableFutureTask<SlideDeck> slideDeck,
int partCount, long mailbox)
{
super(context, id, body, recipients, individualRecipient, dateSent, dateReceived,
@ -75,21 +75,10 @@ public class MediaMmsMessageRecord extends MessageRecord {
return emphasisAdded(context.getString(R.string.MmsMessageRecord_bad_encrypted_mms_message));
} else if (MmsDatabase.Types.isNoRemoteSessionType(type)) {
return emphasisAdded(context.getString(R.string.MmsMessageRecord_mms_message_encrypted_for_non_existing_session));
} else if (getBody().isPlaintext()) {
return emphasisAdded(context.getString(R.string.MessageNotifier_encrypted_message));
}
return super.getDisplayBody();
}
// private static String getBodyFromSlidesIfAvailable(SlideDeck slideDeck) {
// if (slideDeck == null)
// return "";
//
// for (Slide slide : slideDeck.getSlides()) {
// if (slide.hasText())
// return slide.getText();
// }
//
// return "";
// }
}

View File

@ -46,7 +46,7 @@ public abstract class MessageRecord extends DisplayRecord {
private final long id;
private final int deliveryStatus;
public MessageRecord(Context context, long id, String body, Recipients recipients,
public MessageRecord(Context context, long id, Body body, Recipients recipients,
Recipient individualRecipient,
long dateSent, long dateReceived,
long threadId, int deliveryStatus,
@ -80,7 +80,7 @@ public abstract class MessageRecord extends DisplayRecord {
@Override
public SpannableString getDisplayBody() {
return new SpannableString(getBody());
return new SpannableString(getBody().getBody());
}
public long getId() {
@ -119,15 +119,15 @@ public abstract class MessageRecord extends DisplayRecord {
return spannable;
}
public static class GroupData {
public final int groupSize;
public final int groupSentCount;
public final int groupSendFailedCount;
public GroupData(int groupSize, int groupSentCount, int groupSendFailedCount) {
this.groupSize = groupSize;
this.groupSentCount = groupSentCount;
this.groupSendFailedCount = groupSendFailedCount;
}
}
// public static class GroupData {
// public final int groupSize;
// public final int groupSentCount;
// public final int groupSendFailedCount;
//
// public GroupData(int groupSize, int groupSentCount, int groupSendFailedCount) {
// this.groupSize = groupSize;
// this.groupSentCount = groupSentCount;
// this.groupSendFailedCount = groupSendFailedCount;
// }
// }
}

View File

@ -46,7 +46,7 @@ public class NotificationMmsMessageRecord extends MessageRecord {
byte[] contentLocation, long messageSize, long expiry,
int status, byte[] transactionId, long mailbox)
{
super(context, id, "", recipients, individualRecipient, dateSent, dateReceived,
super(context, id, new Body("", true), recipients, individualRecipient, dateSent, dateReceived,
threadId, DELIVERY_STATUS_NONE, mailbox);
this.contentLocation = contentLocation;

View File

@ -36,7 +36,7 @@ import org.thoughtcrime.securesms.recipients.Recipients;
public class SmsMessageRecord extends MessageRecord {
public SmsMessageRecord(Context context, long id,
String body, Recipients recipients,
Body body, Recipients recipients,
Recipient individualRecipient,
long dateSent, long dateReceived,
long type, long threadId,
@ -60,14 +60,16 @@ public class SmsMessageRecord extends MessageRecord {
return emphasisAdded(context.getString(R.string.ConversationListAdapter_key_exchange_message));
} else if (isKeyExchange() && !isOutgoing()) {
return emphasisAdded(context.getString(R.string.ConversationItem_received_key_exchange_message_click_to_process));
} else if (isOutgoing() && Tag.isTagged(getBody())) {
return new SpannableString(Tag.stripTag(getBody()));
} else if (SmsDatabase.Types.isFailedDecryptType(type)) {
return emphasisAdded(context.getString(R.string.MessageDisplayHelper_bad_encrypted_message));
} else if (SmsDatabase.Types.isDecryptInProgressType(type)) {
return emphasisAdded(context.getString(R.string.MessageDisplayHelper_decrypting_please_wait));
} else if (SmsDatabase.Types.isNoRemoteSessionType(type)) {
return emphasisAdded(context.getString(R.string.MessageDisplayHelper_message_encrypted_for_non_existing_session));
} else if (!getBody().isPlaintext()) {
return emphasisAdded(context.getString(R.string.MessageNotifier_encrypted_message));
} else if (isOutgoing() && Tag.isTagged(getBody().getBody())) {
return new SpannableString(Tag.stripTag(getBody().getBody()));
} else {
return super.getDisplayBody();
}

View File

@ -39,7 +39,7 @@ public class ThreadRecord extends DisplayRecord {
private final boolean read;
private final int distributionType;
public ThreadRecord(Context context, String body, Recipients recipients, long date,
public ThreadRecord(Context context, Body body, Recipients recipients, long date,
long count, boolean read, long threadId, long snippetType,
int distributionType)
{
@ -60,11 +60,13 @@ public class ThreadRecord extends DisplayRecord {
return emphasisAdded(context.getString(R.string.MessageDisplayHelper_bad_encrypted_message));
} else if (SmsDatabase.Types.isNoRemoteSessionType(type)) {
return emphasisAdded(context.getString(R.string.MessageDisplayHelper_message_encrypted_for_non_existing_session));
} else if (!getBody().isPlaintext()) {
return emphasisAdded(context.getString(R.string.MessageNotifier_encrypted_message));
} else {
if (Util.isEmpty(getBody())) {
if (Util.isEmpty(getBody().getBody())) {
return new SpannableString(context.getString(R.string.MessageNotifier_no_subject));
} else {
return new SpannableString(getBody());
return new SpannableString(getBody().getBody());
}
}
}

View File

@ -41,11 +41,11 @@ public class OutgoingTextMessage {
public static OutgoingTextMessage from(SmsMessageRecord record) {
if (record.isSecure()) {
return new OutgoingEncryptedMessage(record.getIndividualRecipient(), record.getBody());
return new OutgoingEncryptedMessage(record.getIndividualRecipient(), record.getBody().getBody());
} else if (record.isKeyExchange()) {
return new OutgoingKeyExchangeMessage(record.getIndividualRecipient(), record.getBody());
return new OutgoingKeyExchangeMessage(record.getIndividualRecipient(), record.getBody().getBody());
} else {
return new OutgoingTextMessage(record.getIndividualRecipient(), record.getBody());
return new OutgoingTextMessage(record.getIndividualRecipient(), record.getBody().getBody());
}
}

View File

@ -44,7 +44,7 @@ public class SmsTransport {
OutgoingTextMessage transportMessage = OutgoingTextMessage.from(message);
if (message.isSecure()) {
String encryptedMessage = getAsymmetricEncrypt(masterSecret, message.getBody(),
String encryptedMessage = getAsymmetricEncrypt(masterSecret, message.getBody().getBody(),
message.getIndividualRecipient());
transportMessage = transportMessage.withBody(encryptedMessage);
}
@ -78,7 +78,7 @@ public class SmsTransport {
private void deliverPlaintextMessage(SmsMessageRecord message)
throws UndeliverableMessageException
{
ArrayList<String> messages = SmsManager.getDefault().divideMessage(message.getBody());
ArrayList<String> messages = SmsManager.getDefault().divideMessage(message.getBody().getBody());
ArrayList<PendingIntent> sentIntents = constructSentIntents(message.getId(), message.getType(), messages);
ArrayList<PendingIntent> deliveredIntents = constructDeliveredIntents(message.getId(), message.getType(), messages);
String recipient = message.getIndividualRecipient().getNumber();