Merge pull request #288 from RyanRory/restoration-fix

Fix Restoration From Seed
pull/296/head
Niels Andriesse 5 years ago committed by GitHub
commit 07d26756ca
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23

@ -737,6 +737,7 @@
<string name="MessageDisplayHelper_bad_encrypted_message">Bad encrypted message</string>
<string name="MessageDisplayHelper_message_encrypted_for_non_existing_session">Message encrypted for non-existing session</string>
<string name="MessageRecord_session_restore_sent">You have sent a session restoration request to %s</string>
<string name="MessageRecord_session_restore_done">Secure session reset done</string>
<!-- MmsMessageRecord -->
<string name="MmsMessageRecord_bad_encrypted_mms_message">Bad encrypted MMS message</string>

@ -358,7 +358,7 @@ public class ConversationFragment extends Fragment
if (messageRecord.isGroupAction() || messageRecord.isCallLog() ||
messageRecord.isJoined() || messageRecord.isExpirationTimerUpdate() ||
messageRecord.isEndSession() || messageRecord.isIdentityUpdate() ||
messageRecord.isIdentityVerified() || messageRecord.isIdentityDefault() || messageRecord.isLokiSessionRestoreSent())
messageRecord.isIdentityVerified() || messageRecord.isIdentityDefault() || messageRecord.isLokiSessionRestoreSent() || messageRecord.isLokiSessionRestoreDone())
{
actionMessage = true;
}

@ -114,6 +114,7 @@ public class ConversationUpdateItem extends LinearLayout
else if (messageRecord.isIdentityVerified() ||
messageRecord.isIdentityDefault()) setIdentityVerifyUpdate(messageRecord);
else if (messageRecord.isLokiSessionRestoreSent()) setTextMessageRecord(messageRecord);
else if (messageRecord.isLokiSessionRestoreDone()) setTextMessageRecord(messageRecord);
else throw new AssertionError("Neither group nor log nor joined.");
if (batchSelected.contains(messageRecord)) setSelected(true);

@ -84,6 +84,7 @@ public interface MmsSmsColumns {
// Loki
protected static final long ENCRYPTION_LOKI_SESSION_RESTORE_SENT_BIT = 0x01000000;
protected static final long ENCRYPTION_LOKI_SESSION_RESTORE_DONE_BIT = 0x00100000;
public static boolean isDraftMessageType(long type) {
return (type & BASE_TYPE_MASK) == BASE_DRAFT_TYPE;
@ -237,6 +238,10 @@ public interface MmsSmsColumns {
return (type & ENCRYPTION_LOKI_SESSION_RESTORE_SENT_BIT) != 0;
}
public static boolean isLokiSessionRestoreDoneType(long type) {
return (type & ENCRYPTION_LOKI_SESSION_RESTORE_DONE_BIT) != 0;
}
public static boolean isLegacyType(long type) {
return (type & ENCRYPTION_REMOTE_LEGACY_BIT) != 0 ||
(type & ENCRYPTION_REMOTE_BIT) != 0;

@ -255,6 +255,10 @@ public class SmsDatabase extends MessagingDatabase {
updateTypeBitmask(id, Types.ENCRYPTION_MASK, Types.ENCRYPTION_LOKI_SESSION_RESTORE_SENT_BIT);
}
public void markAsLokiSessionRestorationDone(long id) {
updateTypeBitmask(id, Types.ENCRYPTION_MASK, Types.ENCRYPTION_LOKI_SESSION_RESTORE_DONE_BIT);
}
public void markAsLegacyVersion(long id) {
updateTypeBitmask(id, Types.ENCRYPTION_MASK, Types.ENCRYPTION_REMOTE_LEGACY_BIT);
}

@ -107,6 +107,8 @@ public abstract class DisplayRecord {
public boolean isLokiSessionRestoreSent() { return SmsDatabase.Types.isLokiSessionRestoreSentType(type); }
public boolean isLokiSessionRestoreDone() { return SmsDatabase.Types.isLokiSessionRestoreDoneType(type); }
public boolean isGroupUpdate() {
return SmsDatabase.Types.isGroupUpdate(type);
}

@ -180,7 +180,7 @@ public abstract class MessageRecord extends DisplayRecord {
public boolean isUpdate() {
return isGroupAction() || isJoined() || isExpirationTimerUpdate() || isCallLog() ||
isEndSession() || isIdentityUpdate() || isIdentityVerified() || isIdentityDefault() || isLokiSessionRestoreSent();
isEndSession() || isIdentityUpdate() || isIdentityVerified() || isIdentityDefault() || isLokiSessionRestoreSent() || isLokiSessionRestoreDone();
}
public boolean isMediaPending() {

@ -82,7 +82,9 @@ public class SmsMessageRecord extends MessageRecord {
} else if (SmsDatabase.Types.isNoRemoteSessionType(type)) {
return emphasisAdded(context.getString(R.string.MessageDisplayHelper_message_encrypted_for_non_existing_session));
} else if (isLokiSessionRestoreSent()) {
return emphasisAdded(context.getString(R.string.MessageRecord_session_restore_sent, recipient.toShortString()));
return emphasisAdded(context.getString(R.string.SmsMessageRecord_secure_session_reset));
} else if (isLokiSessionRestoreDone()) {
return emphasisAdded(context.getString(R.string.MessageRecord_session_restore_done));
} else if (isEndSession() && isOutgoing()) {
return emphasisAdded(context.getString(R.string.SmsMessageRecord_secure_session_reset));
} else if (isEndSession()) {

@ -83,7 +83,9 @@ public class ThreadRecord extends DisplayRecord {
} else if (SmsDatabase.Types.isNoRemoteSessionType(type)) {
return emphasisAdded(context.getString(R.string.MessageDisplayHelper_message_encrypted_for_non_existing_session));
} else if (isLokiSessionRestoreSent()) {
return emphasisAdded(context.getString(R.string.MessageRecord_session_restore_sent, recipient.toShortString()));
return emphasisAdded(context.getString(R.string.SmsMessageRecord_secure_session_reset));
} else if (isLokiSessionRestoreDone()) {
return emphasisAdded(context.getString(R.string.MessageRecord_session_restore_done));
} else if (SmsDatabase.Types.isEndSessionType(type)) {
return emphasisAdded(context.getString(R.string.ThreadRecord_secure_session_reset));
} else if (MmsSmsColumns.Types.isLegacyType(type)) {

@ -1073,7 +1073,7 @@ public class PushDecryptJob extends BaseJob implements InjectableType {
@NonNull Optional<Long> smsMessageId, @NonNull Throwable e)
{
SmsDatabase smsDatabase = DatabaseFactory.getSmsDatabase(context);
if (SessionMetaProtocol.shouldErrorMessageShow(context, timestamp)) {
if (!smsMessageId.isPresent()) {
Optional<InsertResult> insertResult = insertPlaceholder(sender, senderDevice, timestamp);
@ -1084,6 +1084,7 @@ public class PushDecryptJob extends BaseJob implements InjectableType {
} else {
smsDatabase.markAsDecryptFailed(smsMessageId.get());
}
}
// FIXME: This is a temporary patch for bad mac issues. At least with this people will be able to message again. We have to figure out the root cause of the issue though.
if (e.getCause() != null) {
@ -1100,14 +1101,14 @@ public class PushDecryptJob extends BaseJob implements InjectableType {
}
}
SessionManagementProtocol.triggerSessionRestorationUI(context, sender);
SessionManagementProtocol.triggerSessionRestorationUI(context, sender, timestamp);
}
private void handleNoSessionMessage(@NonNull String sender, int senderDevice, long timestamp,
@NonNull Optional<Long> smsMessageId)
{
SmsDatabase smsDatabase = DatabaseFactory.getSmsDatabase(context);
if (SessionMetaProtocol.shouldErrorMessageShow(context, timestamp)) {
if (!smsMessageId.isPresent()) {
Optional<InsertResult> insertResult = insertPlaceholder(sender, senderDevice, timestamp);
@ -1118,7 +1119,8 @@ public class PushDecryptJob extends BaseJob implements InjectableType {
} else {
smsDatabase.markAsNoSession(smsMessageId.get());
}
SessionManagementProtocol.triggerSessionRestorationUI(context, sender);
}
SessionManagementProtocol.triggerSessionRestorationUI(context, sender, timestamp);
}
private void handleLegacyMessage(@NonNull String sender, int senderDevice, long timestamp,

@ -307,7 +307,7 @@ class LokiAPIDatabase(context: Context, helper: SQLCipherOpenHelper) : Database(
override fun getSessionRequestSentTimestamp(publicKey: String): Long? {
val database = databaseHelper.readableDatabase
return database.get(sessionRequestSentTimestampTable, "${LokiAPIDatabase.publicKey} = ?", wrap(publicKey)) { cursor ->
cursor.getInt(LokiAPIDatabase.timestamp)
cursor.getLong(LokiAPIDatabase.timestamp)
}?.toLong()
}

@ -62,7 +62,8 @@ object SessionManagementProtocol {
val apiDB = DatabaseFactory.getLokiAPIDatabase(context)
val sentTimestamp = apiDB.getSessionRequestSentTimestamp(publicKey) ?: 0
val processedTimestamp = apiDB.getSessionRequestProcessedTimestamp(publicKey) ?: 0
return timestamp > sentTimestamp && timestamp > processedTimestamp
val restorationTimestamp = TextSecurePreferences.getRestorationTime(context)
return timestamp > sentTimestamp && timestamp > processedTimestamp && timestamp > restorationTimestamp
}
@JvmStatic
@ -99,10 +100,13 @@ object SessionManagementProtocol {
}
@JvmStatic
fun triggerSessionRestorationUI(context: Context, publicKey: String) {
fun triggerSessionRestorationUI(context: Context, publicKey: String, errorTimestamp: Long) {
val masterDevicePublicKey = MultiDeviceProtocol.shared.getMasterDevice(publicKey) ?: publicKey
val masterDeviceAsRecipient = recipient(context, masterDevicePublicKey)
if (masterDeviceAsRecipient.isGroupRecipient) { return }
if (TextSecurePreferences.getRestorationTime(context) > errorTimestamp) {
return ApplicationContext.getInstance(context).sendSessionRequestIfNeeded(publicKey)
}
val threadID = DatabaseFactory.getThreadDatabase(context).getThreadIdFor(masterDeviceAsRecipient)
DatabaseFactory.getLokiThreadDatabase(context).addSessionRestoreDevice(threadID, publicKey)
}

@ -30,6 +30,12 @@ object SessionMetaProtocol {
return shouldIgnoreMessage
}
@JvmStatic
fun shouldErrorMessageShow(context: Context, timestamp: Long): Boolean {
val restorationTimestamp = TextSecurePreferences.getRestorationTime(context)
return timestamp > restorationTimestamp
}
@JvmStatic
fun handleProfileUpdateIfNeeded(context: Context, content: SignalServiceContent) {
val rawDisplayName = content.senderDisplayName.orNull() ?: return

@ -2,7 +2,10 @@ package org.thoughtcrime.securesms.loki.protocol
import android.content.Context
import org.thoughtcrime.securesms.ApplicationContext
import org.thoughtcrime.securesms.database.Address
import org.thoughtcrime.securesms.database.DatabaseFactory
import org.thoughtcrime.securesms.recipients.Recipient
import org.thoughtcrime.securesms.sms.OutgoingTextMessage
import org.whispersystems.libsignal.loki.SessionResetProtocol
import org.whispersystems.libsignal.loki.SessionResetStatus
import org.whispersystems.libsignal.protocol.PreKeySignalMessage
@ -22,7 +25,14 @@ class SessionResetImplementation(private val context: Context) : SessionResetPro
val job = NullMessageSendJob(publicKey)
ApplicationContext.getInstance(context).jobManager.add(job)
}
// TODO: Show session reset succeed message
val smsDB = DatabaseFactory.getSmsDatabase(context)
val recipient = Recipient.from(context, Address.fromSerialized(publicKey), false)
val threadID = DatabaseFactory.getThreadDatabase(context).getThreadIdFor(recipient)
val infoMessage = OutgoingTextMessage(recipient, "", 0, 0)
val infoMessageID = smsDB.insertMessageOutbox(threadID, infoMessage, false, System.currentTimeMillis(), null)
if (infoMessageID > -1) {
smsDB.markAsLokiSessionRestorationDone(infoMessageID)
}
}
override fun validatePreKeySignalMessage(publicKey: String, message: PreKeySignalMessage) {

Loading…
Cancel
Save