mirror of
https://github.com/oxen-io/session-android.git
synced 2024-11-23 18:15:22 +00:00
Handle session restoration.
This commit is contained in:
parent
fd2dc678ea
commit
0caeb3a109
@ -3086,8 +3086,9 @@ public class ConversationActivity extends PassphraseRequiredActionBarActivity
|
||||
@Override
|
||||
public void updateItemButtonPressed(@NonNull MessageRecord messageRecord) {
|
||||
// Loki - User clicked restore session
|
||||
if (messageRecord.isNoRemoteSession() && !messageRecord.isLokiSessionRestoreSent()) {
|
||||
// TODO: Send a message with `SESSION_RESTORE` flag
|
||||
Recipient recipient = messageRecord.getRecipient();
|
||||
if (!recipient.isGroupRecipient() && messageRecord.isNoRemoteSession() && !messageRecord.isLokiSessionRestoreSent()) {
|
||||
MessageSender.sendRestoreSessionMessage(this, recipient.getAddress().serialize());
|
||||
DatabaseFactory.getSmsDatabase(this).markAsLokiSessionRestoreSent(messageRecord.id);
|
||||
TextSecurePreferences.setShowingSessionRestorePrompt(this, messageRecord.getIndividualRecipient().getAddress().serialize(), false);
|
||||
}
|
||||
|
@ -74,6 +74,7 @@ import org.thoughtcrime.securesms.loki.LokiPreKeyBundleDatabase;
|
||||
import org.thoughtcrime.securesms.loki.LokiPreKeyRecordDatabase;
|
||||
import org.thoughtcrime.securesms.loki.LokiThreadDatabase;
|
||||
import org.thoughtcrime.securesms.loki.MultiDeviceUtilities;
|
||||
import org.thoughtcrime.securesms.loki.DebouncerCache;
|
||||
import org.thoughtcrime.securesms.mms.IncomingMediaMessage;
|
||||
import org.thoughtcrime.securesms.mms.MmsException;
|
||||
import org.thoughtcrime.securesms.mms.OutgoingExpirationUpdateMessage;
|
||||
@ -94,6 +95,7 @@ import org.thoughtcrime.securesms.sms.OutgoingEncryptedMessage;
|
||||
import org.thoughtcrime.securesms.sms.OutgoingEndSessionMessage;
|
||||
import org.thoughtcrime.securesms.sms.OutgoingTextMessage;
|
||||
import org.thoughtcrime.securesms.stickers.StickerLocator;
|
||||
import org.thoughtcrime.securesms.util.Debouncer;
|
||||
import org.thoughtcrime.securesms.util.GroupUtil;
|
||||
import org.thoughtcrime.securesms.util.Hex;
|
||||
import org.thoughtcrime.securesms.util.IdentityUtil;
|
||||
@ -337,6 +339,8 @@ public class PushDecryptJob extends BaseJob implements InjectableType {
|
||||
MultiDeviceUtilities.checkForRevocation(context);
|
||||
}
|
||||
} else {
|
||||
// Loki - We shouldn't process session restore message any further
|
||||
if (message.isSessionRestore()) { return; }
|
||||
if (message.isEndSession()) handleEndSessionMessage(content, smsMessageId);
|
||||
else if (message.isGroupUpdate()) handleGroupMessage(content, message, smsMessageId);
|
||||
else if (message.isExpirationUpdate())
|
||||
@ -1187,7 +1191,8 @@ public class PushDecryptJob extends BaseJob implements InjectableType {
|
||||
}
|
||||
|
||||
private void storePreKeyBundleIfNeeded(@NonNull SignalServiceEnvelope envelope, @NonNull SignalServiceContent content) {
|
||||
if (content.lokiServiceMessage.isPresent()) {
|
||||
Recipient sender = Recipient.from(context, Address.fromSerialized(content.getSender()), false);
|
||||
if (!sender.isGroupRecipient() && content.lokiServiceMessage.isPresent()) {
|
||||
LokiServiceMessage lokiMessage = content.lokiServiceMessage.get();
|
||||
if (lokiMessage.getPreKeyBundleMessage() != null) {
|
||||
int registrationID = TextSecurePreferences.getLocalRegistrationId(context);
|
||||
@ -1203,10 +1208,11 @@ public class PushDecryptJob extends BaseJob implements InjectableType {
|
||||
|
||||
// If we got a friend request and we were friends with this user then we need to reset our session
|
||||
if (envelope.isFriendRequest()) {
|
||||
Recipient sender = Recipient.from(context, Address.fromSerialized(content.getSender()), false);
|
||||
long threadID = threadDatabase.getThreadIdIfExistsFor(sender);
|
||||
if (lokiThreadDatabase.getFriendRequestStatus(threadID) == LokiThreadFriendRequestStatus.FRIENDS) {
|
||||
resetSession(content.getSender(), threadID);
|
||||
// Let our other devices know that we have reset session
|
||||
MessageSender.syncContact(context, sender.getAddress());
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -1398,23 +1404,43 @@ public class PushDecryptJob extends BaseJob implements InjectableType {
|
||||
private void handleNoSessionMessage(@NonNull String sender, int senderDevice, long timestamp,
|
||||
@NonNull Optional<Long> smsMessageId)
|
||||
{
|
||||
SmsDatabase smsDatabase = DatabaseFactory.getSmsDatabase(context);
|
||||
Recipient recipient = Recipient.from(context, Address.fromSerialized(sender), false);
|
||||
if (recipient.isGroupRecipient()) { return; }
|
||||
|
||||
if (!smsMessageId.isPresent()) {
|
||||
if (!TextSecurePreferences.isShowingSessionRestorePrompt(context, sender)) {
|
||||
Optional<InsertResult> insertResult = insertPlaceholder(sender, senderDevice, timestamp);
|
||||
long threadID = DatabaseFactory.getThreadDatabase(context).getThreadIdIfExistsFor(recipient);
|
||||
LokiThreadFriendRequestStatus friendRequestStatus = DatabaseFactory.getLokiThreadDatabase(context).getFriendRequestStatus(threadID);
|
||||
/*
|
||||
If we are friends with the user or we sent a friend request to them and we got a message back with no session then we want to try and restore the session automatically.
|
||||
otherwise if we're not friends or our friend request expired then we need to prompt the user for action
|
||||
*/
|
||||
if (friendRequestStatus == LokiThreadFriendRequestStatus.FRIENDS || friendRequestStatus == LokiThreadFriendRequestStatus.REQUEST_SENT) {
|
||||
autoRestoreSession(sender);
|
||||
} else if (friendRequestStatus == LokiThreadFriendRequestStatus.NONE || friendRequestStatus == LokiThreadFriendRequestStatus.REQUEST_EXPIRED) {
|
||||
SmsDatabase smsDatabase = DatabaseFactory.getSmsDatabase(context);
|
||||
|
||||
if (insertResult.isPresent()) {
|
||||
smsDatabase.markAsNoSession(insertResult.get().getMessageId());
|
||||
TextSecurePreferences.setShowingSessionRestorePrompt(context, sender, true);
|
||||
//MessageNotifier.updateNotification(context, insertResult.get().getThreadId());
|
||||
if (!smsMessageId.isPresent()) {
|
||||
if (!TextSecurePreferences.isShowingSessionRestorePrompt(context, sender)) {
|
||||
Optional<InsertResult> insertResult = insertPlaceholder(sender, senderDevice, timestamp);
|
||||
|
||||
if (insertResult.isPresent()) {
|
||||
smsDatabase.markAsNoSession(insertResult.get().getMessageId());
|
||||
TextSecurePreferences.setShowingSessionRestorePrompt(context, sender, true);
|
||||
//MessageNotifier.updateNotification(context, insertResult.get().getThreadId());
|
||||
}
|
||||
}
|
||||
} else {
|
||||
smsDatabase.markAsNoSession(smsMessageId.get());
|
||||
}
|
||||
} else {
|
||||
smsDatabase.markAsNoSession(smsMessageId.get());
|
||||
}
|
||||
}
|
||||
|
||||
private void autoRestoreSession(@NonNull String sender) {
|
||||
// We don't want to keep spamming the user for an auto restore
|
||||
String key = "restore_session_" + sender;
|
||||
Debouncer debouncer = DebouncerCache.getDebouncer(key, 10000);
|
||||
debouncer.publish(() -> MessageSender.sendRestoreSessionMessage(context, sender));
|
||||
}
|
||||
|
||||
private void handleLegacyMessage(@NonNull String sender, int senderDevice, long timestamp,
|
||||
@NonNull Optional<Long> smsMessageId)
|
||||
{
|
||||
|
18
src/org/thoughtcrime/securesms/loki/DebouncerCache.kt
Normal file
18
src/org/thoughtcrime/securesms/loki/DebouncerCache.kt
Normal file
@ -0,0 +1,18 @@
|
||||
package org.thoughtcrime.securesms.loki
|
||||
|
||||
import org.thoughtcrime.securesms.util.Debouncer
|
||||
|
||||
object DebouncerCache {
|
||||
private val cache: HashMap<String, Debouncer> = hashMapOf()
|
||||
@JvmStatic
|
||||
fun getDebouncer(key: String, threshold: Long): Debouncer {
|
||||
val throttler = cache[key] ?: Debouncer(threshold)
|
||||
cache[key] = throttler
|
||||
return throttler
|
||||
}
|
||||
|
||||
@JvmStatic
|
||||
fun remove(key: String) {
|
||||
cache.remove(key)
|
||||
}
|
||||
}
|
@ -27,6 +27,15 @@ object FriendRequestHandler {
|
||||
ActionType.Sent -> LokiThreadFriendRequestStatus.REQUEST_SENT
|
||||
}
|
||||
DatabaseFactory.getLokiThreadDatabase(context).setFriendRequestStatus(threadId, threadFriendStatus)
|
||||
// If we sent a friend request then we need to hide the session restore prompt
|
||||
if (type == ActionType.Sent) {
|
||||
val smsDatabase = DatabaseFactory.getSmsDatabase(context)
|
||||
smsDatabase.getMessages(threadId)
|
||||
.filter { it.isNoRemoteSession && !it.isLokiSessionRestoreSent }
|
||||
.forEach {
|
||||
smsDatabase.markAsLokiSessionRestoreSent(it.id)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Update message status
|
||||
|
@ -13,30 +13,43 @@ import org.whispersystems.signalservice.api.messages.SignalServiceDataMessage
|
||||
import org.whispersystems.signalservice.api.push.SignalServiceAddress
|
||||
import org.whispersystems.signalservice.internal.util.JsonUtil
|
||||
import java.io.IOException
|
||||
import java.lang.IllegalStateException
|
||||
import java.util.concurrent.TimeUnit
|
||||
|
||||
data class BackgroundMessage private constructor(val recipient: String, val body: String?, val friendRequest: Boolean, val unpairingRequest: Boolean) {
|
||||
data class BackgroundMessage private constructor(val data: Map<String, Any>) {
|
||||
companion object {
|
||||
@JvmStatic
|
||||
fun create(recipient: String) = BackgroundMessage(recipient, null, false, false)
|
||||
fun create(recipient: String) = BackgroundMessage(mapOf("recipient" to recipient))
|
||||
@JvmStatic
|
||||
fun createFriendRequest(recipient: String, messageBody: String) = BackgroundMessage(recipient, messageBody, true, false)
|
||||
fun createFriendRequest(recipient: String, messageBody: String) = BackgroundMessage(mapOf(
|
||||
"recipient" to recipient,
|
||||
"body" to messageBody,
|
||||
"friendRequest" to true
|
||||
))
|
||||
@JvmStatic
|
||||
fun createUnpairingRequest(recipient: String) = BackgroundMessage(recipient, null, false, true)
|
||||
fun createUnpairingRequest(recipient: String) = BackgroundMessage(mapOf(
|
||||
"recipient" to recipient,
|
||||
"unpairingRequest" to true
|
||||
))
|
||||
@JvmStatic
|
||||
fun createSessionRestore(recipient: String) = BackgroundMessage(mapOf(
|
||||
"recipient" to recipient,
|
||||
"friendRequest" to true,
|
||||
"sessionRestore" to true
|
||||
))
|
||||
|
||||
internal fun parse(serialized: String): BackgroundMessage {
|
||||
val node = JsonUtil.fromJson(serialized)
|
||||
val recipient = node.get("recipient").asText()
|
||||
val body = if (node.hasNonNull("body")) node.get("body").asText() else null
|
||||
val friendRequest = node.get("friendRequest").asBoolean(false)
|
||||
val unpairingRequest = node.get("unpairingRequest").asBoolean(false)
|
||||
return BackgroundMessage(recipient, body, friendRequest, unpairingRequest)
|
||||
val data = JsonUtil.fromJson(serialized, Map::class.java) as? Map<String, Any> ?: throw AssertionError("JSON parsing failed")
|
||||
return BackgroundMessage(data)
|
||||
}
|
||||
}
|
||||
|
||||
fun <T> get(key: String, defaultValue: T): T {
|
||||
return data[key] as? T ?: defaultValue
|
||||
}
|
||||
|
||||
fun serialize(): String {
|
||||
val map = mapOf("recipient" to recipient, "body" to body, "friendRequest" to friendRequest, "unpairingRequest" to unpairingRequest)
|
||||
return JsonUtil.toJson(map)
|
||||
return JsonUtil.toJson(data)
|
||||
}
|
||||
}
|
||||
|
||||
@ -71,24 +84,31 @@ class PushBackgroundMessageSendJob private constructor(
|
||||
}
|
||||
|
||||
public override fun onRun() {
|
||||
val recipient = message.get<String?>("recipient", null) ?: throw IllegalStateException()
|
||||
val dataMessage = SignalServiceDataMessage.newBuilder()
|
||||
.withTimestamp(System.currentTimeMillis())
|
||||
.withBody(message.body)
|
||||
.withBody(message.get<String?>("body", null))
|
||||
|
||||
if (message.friendRequest) {
|
||||
val bundle = DatabaseFactory.getLokiPreKeyBundleDatabase(context).generatePreKeyBundle(message.recipient)
|
||||
if (message.get("friendRequest", false)) {
|
||||
val bundle = DatabaseFactory.getLokiPreKeyBundleDatabase(context).generatePreKeyBundle(recipient)
|
||||
dataMessage.withPreKeyBundle(bundle)
|
||||
.asFriendRequest(true)
|
||||
} else if (message.unpairingRequest) {
|
||||
}
|
||||
|
||||
if (message.get("unpairingRequest", false)) {
|
||||
dataMessage.asUnpairingRequest(true)
|
||||
}
|
||||
|
||||
if (message.get("sessionRestore", false)) {
|
||||
dataMessage.asSessionRestore(true)
|
||||
}
|
||||
|
||||
val messageSender = ApplicationContext.getInstance(context).communicationModule.provideSignalMessageSender()
|
||||
val address = SignalServiceAddress(message.recipient)
|
||||
val address = SignalServiceAddress(recipient)
|
||||
try {
|
||||
messageSender.sendMessage(-1, address, Optional.absent<UnidentifiedAccessPair>(), dataMessage.build()) // The message ID doesn't matter
|
||||
} catch (e: Exception) {
|
||||
Log.d("Loki", "Failed to send background message to: ${message.recipient}.")
|
||||
Log.d("Loki", "Failed to send background message to: ${recipient}.")
|
||||
throw e
|
||||
}
|
||||
}
|
||||
|
@ -139,6 +139,10 @@ public class MessageSender {
|
||||
public static void sendUnpairRequest(Context context, String contactHexEncodedPublicKey) {
|
||||
ApplicationContext.getInstance(context).getJobManager().add(new PushBackgroundMessageSendJob(BackgroundMessage.createUnpairingRequest(contactHexEncodedPublicKey)));
|
||||
}
|
||||
|
||||
public static void sendRestoreSessionMessage(Context context, String contactHexEncodedPublicKey) {
|
||||
ApplicationContext.getInstance(context).getJobManager().add(new PushBackgroundMessageSendJob(BackgroundMessage.createSessionRestore(contactHexEncodedPublicKey)));
|
||||
}
|
||||
// endregion
|
||||
|
||||
public static long send(final Context context,
|
||||
|
Loading…
Reference in New Issue
Block a user