diff --git a/libsession/src/main/java/org/session/libsession/messaging/sending_receiving/pollers/Poller.kt b/libsession/src/main/java/org/session/libsession/messaging/sending_receiving/pollers/Poller.kt index e9e64fc287..13a1c0e615 100644 --- a/libsession/src/main/java/org/session/libsession/messaging/sending_receiving/pollers/Poller.kt +++ b/libsession/src/main/java/org/session/libsession/messaging/sending_receiving/pollers/Poller.kt @@ -34,6 +34,7 @@ import org.session.libsignal.utilities.Snode import java.security.SecureRandom import java.util.Timer import java.util.TimerTask +import kotlin.time.Duration.Companion.days private class PromiseCanceledException : Exception("Promise canceled.") @@ -176,7 +177,9 @@ class Poller(private val configFactory: ConfigFactoryProtocol, debounceTimer: Ti requestSparseArray[personalMessages.namespace!!] = personalMessages } // get the latest convo info volatile + val hashesToExtend = mutableSetOf() configFactory.getUserConfigs().mapNotNull { config -> + hashesToExtend += config.currentHashes() SnodeAPI.buildAuthenticatedRetrieveBatchRequest( snode, userPublicKey, config.configNamespace() @@ -186,7 +189,19 @@ class Poller(private val configFactory: ConfigFactoryProtocol, debounceTimer: Ti requestSparseArray[request.namespace!!] = request } - val requests = requestSparseArray.valueIterator().asSequence().toList() + val requests = + requestSparseArray.valueIterator().asSequence().toMutableList() + + if (hashesToExtend.isNotEmpty()) { + SnodeAPI.buildAuthenticatedAlterTtlBatchRequest( + messageHashes = hashesToExtend.toList(), + publicKey = userPublicKey, + newExpiry = SnodeAPI.nowWithOffset + 14.days.inWholeMilliseconds, + extend = true + )?.let { extensionRequest -> + requests += extensionRequest + } + } SnodeAPI.getRawBatchResponse(snode, userPublicKey, requests).bind { rawResponses -> isCaughtUp = true diff --git a/libsession/src/main/java/org/session/libsession/snode/SnodeAPI.kt b/libsession/src/main/java/org/session/libsession/snode/SnodeAPI.kt index c0f2a47356..a6cc9147ec 100644 --- a/libsession/src/main/java/org/session/libsession/snode/SnodeAPI.kt +++ b/libsession/src/main/java/org/session/libsession/snode/SnodeAPI.kt @@ -493,6 +493,20 @@ object SnodeAPI { ) } + fun buildAuthenticatedAlterTtlBatchRequest( + messageHashes: List, + newExpiry: Long, + publicKey: String, + shorten: Boolean = false, + extend: Boolean = false): SnodeBatchRequestInfo? { + val params = buildAlterTtlParams(messageHashes, newExpiry, publicKey, extend, shorten) ?: return null + return SnodeBatchRequestInfo( + Snode.Method.Expire.rawValue, + params, + null + ) + } + fun getRawBatchResponse(snode: Snode, publicKey: String, requests: List, sequence: Boolean = false): RawResponsePromise { val parameters = mutableMapOf( "requests" to requests @@ -533,8 +547,24 @@ object SnodeAPI { } fun alterTtl(messageHashes: List, newExpiry: Long, publicKey: String, extend: Boolean = false, shorten: Boolean = false): RawResponsePromise { - val userEd25519KeyPair = MessagingModuleConfiguration.shared.getUserED25519KeyPair() ?: return Promise.ofFail(NullPointerException("No user key pair")) return retryIfNeeded(maxRetryCount) { + val params = buildAlterTtlParams(messageHashes, newExpiry, publicKey, extend, shorten) + ?: return@retryIfNeeded Promise.ofFail( + Exception("Couldn't build signed params for alterTtl request for newExpiry=$newExpiry, extend=$extend, shorten=$shorten") + ) + getSingleTargetSnode(publicKey).bind { snode -> + invoke(Snode.Method.Expire, snode, params, publicKey) + } + } + } + + private fun buildAlterTtlParams( // TODO: in future this will probably need to use the closed group subkeys / admin keys for group swarms + messageHashes: List, + newExpiry: Long, + publicKey: String, + extend: Boolean = false, + shorten: Boolean = false): Map? { + val userEd25519KeyPair = MessagingModuleConfiguration.shared.getUserED25519KeyPair() ?: return null val params = mutableMapOf( "expiry" to newExpiry, "messages" to messageHashes, @@ -559,16 +589,13 @@ object SnodeAPI { ) } catch (e: Exception) { Log.e("Loki", "Signing data failed with user secret key", e) - return@retryIfNeeded Promise.ofFail(e) + return null } params["pubkey"] = publicKey params["pubkey_ed25519"] = ed25519PublicKey params["signature"] = Base64.encodeBytes(signature) - getSingleTargetSnode(publicKey).bind { snode -> - invoke(Snode.Method.Expire, snode, params, publicKey) - } - } + return params } fun getMessages(publicKey: String): MessageListPromise {