Fix various session reset issues

This commit is contained in:
nielsandriesse 2020-05-22 13:41:36 +10:00
parent 9b329cbd34
commit a7b94d188f
10 changed files with 35 additions and 36 deletions

View File

@ -490,7 +490,7 @@ public class ApplicationContext extends MultiDexApplication implements Dependenc
LokiAPI.Companion.configureIfNeeded(userPublicKey, apiDB, broadcaster);
lokiPoller = new LokiPoller(userPublicKey, apiDB, protos -> {
for (SignalServiceProtos.Envelope proto : protos) {
new PushContentReceiveJob(context).processEnvelope(new SignalServiceEnvelope(proto));
new PushContentReceiveJob(context).processEnvelope(new SignalServiceEnvelope(proto), false);
}
return Unit.INSTANCE;
});

View File

@ -207,7 +207,7 @@ public class PushDecryptJob extends BaseJob implements InjectableType {
SignalServiceEnvelope envelope = database.get(messageId);
Optional<Long> optionalSmsMessageId = smsMessageId > 0 ? Optional.of(smsMessageId) : Optional.absent();
handleMessage(envelope, optionalSmsMessageId);
handleMessage(envelope, optionalSmsMessageId, false);
database.delete(messageId);
}
}
@ -222,7 +222,7 @@ public class PushDecryptJob extends BaseJob implements InjectableType {
}
public void processMessage(@NonNull SignalServiceEnvelope envelope) {
public void processMessage(@NonNull SignalServiceEnvelope envelope, boolean isPushNotification) {
synchronized (PushReceivedJob.RECEIVE_LOCK) {
if (needsMigration()) {
Log.w(TAG, "Skipping and storing envelope, waiting for migration...");
@ -231,7 +231,7 @@ public class PushDecryptJob extends BaseJob implements InjectableType {
return;
}
handleMessage(envelope, Optional.absent());
handleMessage(envelope, Optional.absent(), isPushNotification);
}
}
@ -253,7 +253,7 @@ public class PushDecryptJob extends BaseJob implements InjectableType {
}
private void handleMessage(@NonNull SignalServiceEnvelope envelope, @NonNull Optional<Long> smsMessageId) {
private void handleMessage(@NonNull SignalServiceEnvelope envelope, @NonNull Optional<Long> smsMessageId, boolean isPushNotification) {
try {
GroupDatabase groupDatabase = DatabaseFactory.getGroupDatabase(context);
SignalProtocolStore axolotlStore = new SignalProtocolStoreImpl(context);
@ -378,7 +378,9 @@ public class PushDecryptJob extends BaseJob implements InjectableType {
handleInvalidVersionMessage(e.getSender(), e.getSenderDevice(), envelope.getTimestamp(), smsMessageId);
} catch (ProtocolInvalidMessageException e) {
Log.w(TAG, e);
if (!isPushNotification) { // This can be triggered if a PN encrypted with an old session comes in after the user performed a session reset
handleCorruptMessage(e.getSender(), e.getSenderDevice(), envelope.getTimestamp(), smsMessageId);
}
} catch (ProtocolInvalidKeyIdException | ProtocolInvalidKeyException | ProtocolUntrustedIdentityException e) {
Log.w(TAG, e);
handleCorruptMessage(e.getSender(), e.getSenderDevice(), envelope.getTimestamp(), smsMessageId);

View File

@ -57,7 +57,7 @@ public class PushNotificationReceiveJob extends PushReceivedJob implements Injec
synchronized (PushReceivedJob.RECEIVE_LOCK) {
receiver.retrieveMessages(envelope -> {
Log.i(tag, "Retrieved an envelope." + timeSuffix(startTime));
processEnvelope(envelope);
processEnvelope(envelope, false);
Log.i(tag, "Successfully processed an envelope." + timeSuffix(startTime));
});
TextSecurePreferences.setNeedsMessagePull(context, false);

View File

@ -22,7 +22,7 @@ public abstract class PushReceivedJob extends BaseJob {
super(parameters);
}
public void processEnvelope(@NonNull SignalServiceEnvelope envelope) {
public void processEnvelope(@NonNull SignalServiceEnvelope envelope, boolean isPushNotification) {
synchronized (RECEIVE_LOCK) {
try {
if (envelope.hasSource()) {
@ -37,7 +37,7 @@ public abstract class PushReceivedJob extends BaseJob {
if (envelope.isReceipt()) {
handleReceipt(envelope);
} else if (envelope.isPreKeySignalMessage() || envelope.isSignalMessage() || envelope.isUnidentifiedSender() || envelope.isFriendRequest()) {
handleMessage(envelope);
handleMessage(envelope, isPushNotification);
} else {
Log.w(TAG, "Received envelope of unknown type: " + envelope.getType());
}
@ -47,8 +47,8 @@ public abstract class PushReceivedJob extends BaseJob {
}
}
private void handleMessage(SignalServiceEnvelope envelope) {
new PushDecryptJob(context).processMessage(envelope);
private void handleMessage(SignalServiceEnvelope envelope, boolean isPushNotification) {
new PushDecryptJob(context).processMessage(envelope, isPushNotification);
}
@SuppressLint("DefaultLocale")

View File

@ -38,7 +38,7 @@ class BackgroundPollWorker : PersistentAlarmManagerListener() {
LokiAPI.configureIfNeeded(userHexEncodedPublicKey, lokiAPIDatabase, broadcaster)
LokiAPI.shared.getMessages().map { messages ->
messages.forEach {
PushContentReceiveJob(context).processEnvelope(SignalServiceEnvelope(it))
PushContentReceiveJob(context).processEnvelope(SignalServiceEnvelope(it), false)
}
}
} catch (exception: Throwable) {

View File

@ -24,7 +24,7 @@ class PushNotificationService : FirebaseMessagingService() {
if (data != null) {
try {
val envelope = LokiMessageWrapper.unwrap(data)
PushContentReceiveJob(this).processEnvelope(SignalServiceEnvelope(envelope))
PushContentReceiveJob(this).processEnvelope(SignalServiceEnvelope(envelope), true)
} catch (e: Exception) {
Log.d("Loki", "Failed to unwrap data for message.")
}

View File

@ -2,7 +2,6 @@ package org.thoughtcrime.securesms.loki.protocol
import android.content.Context
import android.util.Log
import network.loki.messenger.BuildConfig
import nl.komponents.kovenant.Promise
import org.thoughtcrime.securesms.ApplicationContext
import org.thoughtcrime.securesms.crypto.IdentityKeyUtil
@ -34,21 +33,21 @@ object MultiDeviceProtocol {
enum class MessageType { Text, Media }
@JvmStatic
fun sendTextPush(context: Context, recipient: Recipient, messageID: Long) {
sendMessagePush(context, recipient, messageID, MessageType.Text)
fun sendTextPush(context: Context, recipient: Recipient, messageID: Long, isEndSession: Boolean) {
sendMessagePush(context, recipient, messageID, MessageType.Text, isEndSession)
}
@JvmStatic
fun sendMediaPush(context: Context, recipient: Recipient, messageID: Long) {
sendMessagePush(context, recipient, messageID, MessageType.Media)
sendMessagePush(context, recipient, messageID, MessageType.Media, false)
}
private fun sendMessagePushToDevice(context: Context, recipient: Recipient, messageID: Long, messageType: MessageType): PushSendJob {
private fun sendMessagePushToDevice(context: Context, recipient: Recipient, messageID: Long, messageType: MessageType, isEndSession: Boolean): PushSendJob {
val threadID = DatabaseFactory.getThreadDatabase(context).getThreadIdFor(recipient)
val threadFRStatus = DatabaseFactory.getLokiThreadDatabase(context).getFriendRequestStatus(threadID)
val isNoteToSelf = SessionMetaProtocol.shared.isNoteToSelf(recipient.address.serialize())
val isContactFriend = (threadFRStatus == LokiThreadFriendRequestStatus.FRIENDS || isNoteToSelf) // In the note to self case the device linking request was the FR
val isFRMessage = !isContactFriend // Holds true assuming this method isn't invoked for control messages
val isFRMessage = !isContactFriend
val hasVisibleContent = when (messageType) {
MessageType.Text -> DatabaseFactory.getSmsDatabase(context).getMessage(messageID).body.isNotBlank()
MessageType.Media -> {
@ -56,10 +55,9 @@ object MultiDeviceProtocol {
outgoingMediaMessage.body.isNotBlank() || outgoingMediaMessage.attachments.isNotEmpty()
}
}
if (isFRMessage && !hasVisibleContent && BuildConfig.DEBUG) { throw IllegalStateException() } // Verify the above assumption
val shouldSendAutoGeneratedFR = !isContactFriend && !isFRMessage
&& !isNoteToSelf && !recipient.address.isGroup // Group threads work through session requests
&& hasVisibleContent
&& hasVisibleContent && !isEndSession
if (!shouldSendAutoGeneratedFR) {
when (messageType) {
MessageType.Text -> return PushTextSendJob(messageID, messageID, recipient.address, isFRMessage, null)
@ -74,7 +72,7 @@ object MultiDeviceProtocol {
}
}
private fun sendMessagePush(context: Context, recipient: Recipient, messageID: Long, messageType: MessageType) {
private fun sendMessagePush(context: Context, recipient: Recipient, messageID: Long, messageType: MessageType, isEndSession: Boolean) {
val jobManager = ApplicationContext.getInstance(context).jobManager
val isMultiDeviceRequired = !recipient.address.isOpenGroup
if (!isMultiDeviceRequired) {
@ -86,7 +84,7 @@ object MultiDeviceProtocol {
val publicKey = recipient.address.serialize()
LokiFileServerAPI.shared.getDeviceLinks(publicKey).success {
val devices = MultiDeviceProtocol.shared.getAllLinkedDevices(publicKey)
val jobs = devices.map { sendMessagePushToDevice(context, recipient(context, it), messageID, messageType) }
val jobs = devices.map { sendMessagePushToDevice(context, recipient(context, it), messageID, messageType, isEndSession) }
@Suppress("UNCHECKED_CAST")
when (messageType) {
MessageType.Text -> jobManager.startChain(jobs).enqueue()

View File

@ -89,7 +89,6 @@ object SessionManagementProtocol {
@JvmStatic
fun handleEndSessionMessageIfNeeded(context: Context, content: SignalServiceContent) {
if (!content.dataMessage.isPresent || !content.dataMessage.get().isEndSession) { return }
// TODO: Notify the user
val sessionStore = TextSecureSessionStore(context)
val lokiThreadDB = DatabaseFactory.getLokiThreadDatabase(context)
Log.d("Loki", "Received a session reset request from: ${content.sender}; archiving the session.")

View File

@ -12,15 +12,13 @@ import android.support.annotation.Nullable;
import android.support.v4.app.NotificationCompat;
import android.support.v4.content.ContextCompat;
import org.thoughtcrime.securesms.ApplicationContext;
import org.thoughtcrime.securesms.dependencies.InjectableType;
import org.thoughtcrime.securesms.jobmanager.ConstraintObserver;
import org.thoughtcrime.securesms.jobmanager.impl.NetworkConstraint;
import org.thoughtcrime.securesms.jobmanager.impl.NetworkConstraintObserver;
import org.thoughtcrime.securesms.logging.Log;
import org.thoughtcrime.securesms.ApplicationContext;
import network.loki.messenger.R;
import org.thoughtcrime.securesms.dependencies.InjectableType;
import org.thoughtcrime.securesms.jobs.PushContentReceiveJob;
import org.thoughtcrime.securesms.logging.Log;
import org.thoughtcrime.securesms.notifications.NotificationChannels;
import org.thoughtcrime.securesms.push.SignalServiceNetworkAccess;
import org.thoughtcrime.securesms.util.TextSecurePreferences;
@ -33,6 +31,8 @@ import java.util.concurrent.TimeoutException;
import javax.inject.Inject;
import network.loki.messenger.R;
public class IncomingMessageObserver implements InjectableType, ConstraintObserver.Notifier {
private static final String TAG = IncomingMessageObserver.class.getSimpleName();
@ -159,7 +159,7 @@ public class IncomingMessageObserver implements InjectableType, ConstraintObserv
localPipe.read(REQUEST_TIMEOUT_MINUTES, TimeUnit.MINUTES,
envelope -> {
Log.i(TAG, "Retrieved envelope! " + String.valueOf(envelope.getSource()));
new PushContentReceiveJob(context).processEnvelope(envelope);
new PushContentReceiveJob(context).processEnvelope(envelope, false);
});
} catch (TimeoutException e) {
Log.w(TAG, "Application level read timeout...");

View File

@ -81,7 +81,7 @@ public class MessageSender {
FriendRequestProtocol.setFriendRequestStatusToSendingIfNeeded(context, messageId, allocatedThreadId);
}
sendTextMessage(context, recipient, forceSms, keyExchange, messageId);
sendTextMessage(context, recipient, forceSms, keyExchange, messageId, message.isEndSession());
return allocatedThreadId;
}
@ -135,7 +135,7 @@ public class MessageSender {
if (messageRecord.isMms()) {
sendMediaMessage(context, recipient, forceSms, messageId, expiresIn);
} else {
sendTextMessage(context, recipient, forceSms, keyExchange, messageId);
sendTextMessage(context, recipient, forceSms, keyExchange, messageId, messageRecord.isEndSession());
}
}
@ -152,17 +152,17 @@ public class MessageSender {
private static void sendTextMessage(Context context, Recipient recipient,
boolean forceSms, boolean keyExchange,
long messageId)
long messageId, boolean isEndSession)
{
if (isLocalSelfSend(context, recipient, forceSms)) {
sendLocalTextSelf(context, messageId);
} else {
sendTextPush(context, recipient, messageId);
sendTextPush(context, recipient, messageId, isEndSession);
}
}
private static void sendTextPush(Context context, Recipient recipient, long messageId) {
MultiDeviceProtocol.sendTextPush(context, recipient, messageId);
private static void sendTextPush(Context context, Recipient recipient, long messageId, boolean isEndSession) {
MultiDeviceProtocol.sendTextPush(context, recipient, messageId, isEndSession);
}
private static void sendMediaPush(Context context, Recipient recipient, long messageId) {