From dbb83d86e3ecf6368fee3eb49ba487fc150c45a6 Mon Sep 17 00:00:00 2001 From: gram-signal <84339875+gram-signal@users.noreply.github.com> Date: Fri, 15 May 2026 11:43:05 -0700 Subject: [PATCH] Add remote config for requirePqRatio. --- .../storage/TextSecureSessionStore.java | 5 ++- .../messages/protocol/BufferedSessionStore.kt | 3 +- .../securesms/util/RemoteConfig.kt | 37 +++++++++++++++++++ 3 files changed, 42 insertions(+), 3 deletions(-) diff --git a/app/src/main/java/org/thoughtcrime/securesms/crypto/storage/TextSecureSessionStore.java b/app/src/main/java/org/thoughtcrime/securesms/crypto/storage/TextSecureSessionStore.java index cf3f46b8cd..7228ba2b2c 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/crypto/storage/TextSecureSessionStore.java +++ b/app/src/main/java/org/thoughtcrime/securesms/crypto/storage/TextSecureSessionStore.java @@ -12,6 +12,7 @@ import org.thoughtcrime.securesms.database.SessionTable; import org.thoughtcrime.securesms.database.SignalDatabase; import org.thoughtcrime.securesms.recipients.Recipient; import org.thoughtcrime.securesms.recipients.RecipientId; +import org.thoughtcrime.securesms.util.RemoteConfig; import org.whispersystems.signalservice.api.SignalServiceSessionStore; import org.whispersystems.signalservice.api.SignalSessionLock; import org.signal.core.models.ServiceId; @@ -76,7 +77,7 @@ public class TextSecureSessionStore implements SignalServiceSessionStore { try (SignalSessionLock.Lock unused = ReentrantSessionLock.INSTANCE.acquire()) { SessionRecord sessionRecord = SignalDatabase.sessions().load(accountId, address); - return sessionRecord != null && sessionRecord.hasSenderChain(0.0); + return sessionRecord != null && sessionRecord.hasSenderChain(RemoteConfig.requirePqRatio()); } } @@ -188,6 +189,6 @@ public class TextSecureSessionStore implements SignalServiceSessionStore { } private static boolean isActive(@Nullable SessionRecord record) { - return record != null && record.hasSenderChain(0.0); + return record != null && record.hasSenderChain(RemoteConfig.requirePqRatio()); } } diff --git a/app/src/main/java/org/thoughtcrime/securesms/messages/protocol/BufferedSessionStore.kt b/app/src/main/java/org/thoughtcrime/securesms/messages/protocol/BufferedSessionStore.kt index a86608ecc9..253ed94c93 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/messages/protocol/BufferedSessionStore.kt +++ b/app/src/main/java/org/thoughtcrime/securesms/messages/protocol/BufferedSessionStore.kt @@ -5,6 +5,7 @@ import org.signal.libsignal.protocol.NoSessionException import org.signal.libsignal.protocol.SignalProtocolAddress import org.signal.libsignal.protocol.state.SessionRecord import org.thoughtcrime.securesms.database.SignalDatabase +import org.thoughtcrime.securesms.util.RemoteConfig import org.whispersystems.signalservice.api.SignalServiceAccountDataStore import org.whispersystems.signalservice.api.SignalServiceSessionStore import kotlin.jvm.Throws @@ -76,7 +77,7 @@ class BufferedSessionStore(private val selfServiceId: ServiceId) : SignalService if (fromDatabase != null) { store[address] = fromDatabase - return fromDatabase.hasSenderChain(0.0) + return fromDatabase.hasSenderChain(RemoteConfig.requirePqRatio) } else { false } diff --git a/app/src/main/java/org/thoughtcrime/securesms/util/RemoteConfig.kt b/app/src/main/java/org/thoughtcrime/securesms/util/RemoteConfig.kt index 0d97edee0e..592fed7f68 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/util/RemoteConfig.kt +++ b/app/src/main/java/org/thoughtcrime/securesms/util/RemoteConfig.kt @@ -369,6 +369,13 @@ object RemoteConfig { } } + private fun Any?.asDouble(defaultValue: Double): Double { + return when (this) { + is String -> this.toDoubleOrNull() ?: defaultValue + else -> defaultValue + } + } + private fun Any?.asString(defaultValue: T): T { @Suppress("UNCHECKED_CAST") return when (this) { @@ -486,6 +493,23 @@ object RemoteConfig { ) } + private fun remoteDouble( + key: String, + defaultValue: Double, + hotSwappable: Boolean, + active: Boolean = true, + onChangeListener: OnFlagChange? = null + ): Config { + return remoteValue( + key = key, + hotSwappable = hotSwappable, + sticky = false, + active = active, + onChangeListener = onChangeListener, + transformer = { it.asDouble(defaultValue) } + ) + } + private fun remoteDuration( key: String, defaultValue: Duration, @@ -1387,5 +1411,18 @@ object RemoteConfig { hotSwappable = true ) + /** + * A ratio between 0 and 1, where 0 means that a session is never archived due + * to a lack of PQ, and 1 means that a session is always archived due to a + * lack of PQ. + */ + @JvmStatic + @get:JvmName("requirePqRatio") + val requirePqRatio: Double by remoteDouble( + key = "android.requirePqRatio", + defaultValue = 0.0, + hotSwappable = true + ) + // endregion }