From fc0dff18cab03439068be88f094e8f2d561102b3 Mon Sep 17 00:00:00 2001 From: Paul Hitt Date: Tue, 1 Sep 2026 15:28:17 -0400 Subject: [PATCH] Sign-in loads the identity it already has MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 🔴 **This is why signing out and back in broke everything.** Sign-in only ever consulted the in-memory `identity` field, and sign-out clears it — so it minted a fresh `DeviceIdentity` and OVERWROTE the vault's, making this phone a brand new device on every single sign-in. Everything the owner hit follows from that one line: - contacts saw a safety-number change and had to accept new keys; - the account accumulated a registered device per sign-in, and fan-out is per device, so half of everything sent to this account went to a mailbox nobody reads — which is why the failures looked random and different each time; - the relay's public key log had not caught up with a key registered seconds earlier, so even after accepting, the next send failed on "the keys offered by this contact are not in the public log". ⚠️ It was harmless until it wasn't. Sign-out used to destroy the vault, so there was never a stored identity to find and minting one was correct. Keeping the device across a plain sign-out — which is what makes signing out cheap — is what turned this into the bug it always looked like. The two changes had to land together and only one did. Co-Authored-By: Claude Opus 4.8 --- .../messenger/app/MessengerViewModel.kt | 24 +++++++++++++++---- 1 file changed, 20 insertions(+), 4 deletions(-) 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 43b5ca2..620f1a1 100644 --- a/app/src/main/kotlin/io/flamenet/messenger/app/MessengerViewModel.kt +++ b/app/src/main/kotlin/io/flamenet/messenger/app/MessengerViewModel.kt @@ -506,10 +506,26 @@ class MessengerViewModel(app: Application) : AndroidViewModel(app) { } val vault = vault ?: error("the vault is not open") - val device = identity ?: DeviceIdentity.create().also { - vault.saveIdentity(it) - identity = it - } + // 🔴 **The stored identity FIRST, and this line is why signing out and + // back in used to cost every contact a prompt.** Sign-in only ever + // consulted the in-memory field, and sign-out clears it — so it minted + // a fresh identity and overwrote the vault's, making this phone a brand + // new device on every sign-in. Contacts saw a safety-number change, + // sends were refused until they accepted it, and the relay's public key + // log had not yet caught up with the key being offered, so even after + // accepting, the next send failed on "the keys offered by this contact + // are not in the public log". + // + // ⚠️ It was harmless right up until it wasn't: sign-out used to destroy + // the vault, so there was never a stored identity to find and minting + // one was correct. Keeping the device across a plain sign-out is what + // turned this into the bug it always looked like. + val device = identity + ?: vault.loadIdentity()?.also { identity = it } + ?: DeviceIdentity.create().also { + vault.saveIdentity(it) + identity = it + } val relay = RelayClient(config.baseUrl, username = account.username, appPassword = credential) relay.useRelayAuth(device)