diff --git a/app/src/main/kotlin/io/flamenet/messenger/app/MediaSettings.kt b/app/src/main/kotlin/io/flamenet/messenger/app/MediaSettings.kt index ff25b6c..a4e0fe5 100644 --- a/app/src/main/kotlin/io/flamenet/messenger/app/MediaSettings.kt +++ b/app/src/main/kotlin/io/flamenet/messenger/app/MediaSettings.kt @@ -24,6 +24,27 @@ class MediaSettings(context: Context) { get() = prefs.getBoolean(FULL_QUALITY, false) set(value) = prefs.edit().putBoolean(FULL_QUALITY, value).apply() + /** + * Refuse to send unless the relay can prove the recipient's keys appear in + * the log it publishes. + * + * 🔴 **This lives here because it was not stored anywhere at all.** It was + * a plain in-memory field on the trust object, set from the switch and + * never written down, so it reverted to off on every launch. A person who + * turned it on was protected until they next closed the app, and nothing + * told them it had lapsed — the switch simply read off again, and a + * setting that quietly disarms itself is worse than one that was never + * offered. iOS has always persisted this in UserDefaults; Android had + * nothing. + * + * ⚠️ Still off by default, deliberately. A relay older than the + * transparency log has no log to prove anything against, so enforcing it + * everywhere would refuse every peer on those deployments. + */ + var requireKeyLog: Boolean + get() = prefs.getBoolean(REQUIRE_KEY_LOG, false) + set(value) = prefs.edit().putBoolean(REQUIRE_KEY_LOG, value).apply() + /** * Generate a preview card when sending a link. * @@ -38,6 +59,7 @@ class MediaSettings(context: Context) { companion object { private const val PREFS = "media-settings" + private const val REQUIRE_KEY_LOG = "requireKeyLog" private const val FULL_QUALITY = "full_quality" private const val LINK_PREVIEWS = "link_previews" } diff --git a/app/src/main/kotlin/io/flamenet/messenger/app/MessengerViewModel.kt b/app/src/main/kotlin/io/flamenet/messenger/app/MessengerViewModel.kt index 25a3e47..e137ec7 100644 --- a/app/src/main/kotlin/io/flamenet/messenger/app/MessengerViewModel.kt +++ b/app/src/main/kotlin/io/flamenet/messenger/app/MessengerViewModel.kt @@ -481,6 +481,15 @@ class MessengerViewModel(app: Application) : AndroidViewModel(app) { val fetchedBuddies = runCatching { session!!.roster() } val fetchedGroups = runCatching { session!!.relay.listGroups() } + + // 🔴 Restore the strict key-log requirement the user chose. Without + // this it reverted to off on every launch: the switch was read from a + // field that only ever existed in memory, so somebody who turned it on + // was protected until they next closed the app and was never told it + // had lapsed. + val strictKeyLog = MediaSettings(getApplication()).requireKeyLog + session!!.conversations.trust.requireKeyLog = strictKeyLog + return Phase.SignedIn( handle = account.username, userId = account.userId, @@ -488,6 +497,11 @@ class MessengerViewModel(app: Application) : AndroidViewModel(app) { relay = config.host, fnid = fnid, status = "Registered with ${preKeys.size} one-time prekeys published.", + // ⚠️ The switch has to read what is actually enforced. Restoring + // the trust object without this would leave the toggle showing off + // while sends were being refused, which is the same confusion in + // the opposite direction. + requireKeyLog = strictKeyLog, buddies = fetchedBuddies.getOrDefault(emptyList()), buddiesLoaded = fetchedBuddies.isSuccess, avatars = session?.avatars( @@ -664,6 +678,9 @@ class MessengerViewModel(app: Application) : AndroidViewModel(app) { * Pinning is always on regardless; this is the stricter, opt-in half. */ fun setRequireKeyLog(required: Boolean) { + // Written down as well as applied. See MediaSettings.requireKeyLog for + // why: this used to be memory-only and silently lapsed on restart. + MediaSettings(getApplication()).requireKeyLog = required session?.conversations?.trust?.requireKeyLog = required update { it.copy(requireKeyLog = required) } }