package io.flamenet.e2e import javax.crypto.KeyGenerator import kotlin.test.Test import kotlin.test.assertEquals import kotlin.test.assertFalse import kotlin.test.assertTrue /** * What the vault remembers about several mailboxes. * * 🔴 **Two of these keys are chosen by whoever writes to you.** An envelope id * comes from the sender, so an unbounded list of them is storage anybody on the * federation can grow — and a relay name comes from a signed record, so a * per-relay entry can be created by anyone who can get a record published. Both * are bounded or scoped deliberately, and that is worth asserting rather than * trusting to a comment. */ class MailboxStateTest { private class MapStorage : Vault.Storage { val records = LinkedHashMap() override fun read(name: String) = records[name] override fun write(name: String, bytes: ByteArray) { records[name] = bytes } override fun delete(name: String) { records.remove(name) } override fun names() = records.keys.toList() } private val storage = MapStorage() /// Held so a SECOND vault can be opened over the same storage — which is /// what a restart is, and the only way to test that anything persisted. private val key = KeyGenerator.getInstance("AES").apply { init(256) }.generateKey() private val vault = Vault(storage, key) // MARK: - Envelope ids @Test fun `an envelope is remembered once and recognised again`() { assertFalse(vault.hasSeenEnvelope("env-1")) vault.rememberEnvelope("env-1") assertTrue(vault.hasSeenEnvelope("env-1")) assertFalse(vault.hasSeenEnvelope("env-2")) } /** * It survives a restart, or a copy at a backup home is read twice on the * first poll after every launch. * * ⚠️ Written with one vault and read with a SECOND over the same storage, * which is what a restart actually is. The first version of this test * asserted that two objects were not the same object, which is true of any * two objects and proves nothing about persistence. */ @Test fun `what was seen survives reopening the vault`() { vault.rememberEnvelope("env-1") val restarted = Vault(storage, key) assertTrue(restarted.hasSeenEnvelope("env-1"), "the dedupe list did not persist") assertFalse(restarted.hasSeenEnvelope("env-2")) } /** The same for everything else a mailbox needs across a launch. */ @Test fun `mailboxes and their cursors survive reopening the vault`() { vault.saveExtraHomes(listOf(Vault.ExtraHome("a.example.com", "me", "pw"))) vault.setWatermarkFor("a.example.com", 900) vault.rememberKeyLogServed("a.example.com") val restarted = Vault(storage, key) assertEquals(listOf("a.example.com"), restarted.extraHomes().map { it.relay }) assertEquals(900, restarted.watermarkFor("a.example.com")) assertTrue(restarted.keyLogServed("a.example.com")) } /** * 🔴 **The key comes from whoever wrote to us.** Oldest first, so a * forgotten id can at worst show a very old message twice — far better than * a list anybody can grow without limit. */ @Test fun `the list of seen envelopes is bounded`() { for (i in 0 until 2_500) vault.rememberEnvelope("env-$i") assertTrue(vault.hasSeenEnvelope("env-2499"), "the newest must be remembered") assertFalse(vault.hasSeenEnvelope("env-0"), "the list grew without limit") } @Test fun `remembering the same id twice does not grow the list`() { repeat(50) { vault.rememberEnvelope("env-same") } vault.rememberEnvelope("env-other") assertTrue(vault.hasSeenEnvelope("env-same")) assertTrue(vault.hasSeenEnvelope("env-other")) } // MARK: - Per-relay state /** * 🔴 Envelope ids come from each relay's own database, so id 40 there says * nothing about id 40 here. One shared cursor would let the first mailbox's * progress silently skip the second's mail. */ @Test fun `each relay keeps its own watermark`() { vault.setWatermarkFor("a.example.com", 900) assertEquals(900, vault.watermarkFor("a.example.com")) assertEquals(0, vault.watermarkFor("b.example.com")) assertEquals(0, vault.inboxWatermark, "the signed-in relay's cursor is separate again") } /** * 🔴 A single global flag meant that signing in to a second relay which * keeps no log read as the FIRST going quiet — a fork warning against an * honest deployment, and every contact on it unreachable. */ @Test fun `the served flag is per relay`() { assertFalse(vault.keyLogServed("a.example.com")) vault.rememberKeyLogServed("a.example.com") assertTrue(vault.keyLogServed("a.example.com")) assertFalse(vault.keyLogServed("b.example.com")) } /** * ⚠️ The pin falls back to the pre-2026-08-30 global entry, so a phone * already holding one keeps it rather than starting trust-on-first-use * again — and a per-relay entry, once written, wins. */ @Test fun `an existing global pin is inherited until a per-relay one is written`() { vault.saveKeyLogPin(Vault.KeyLogPin(4, "old-root")) assertEquals("old-root", vault.loadKeyLogPin("a.example.com")?.root) vault.saveKeyLogPin(Vault.KeyLogPin(9, "new-root"), "a.example.com") assertEquals("new-root", vault.loadKeyLogPin("a.example.com")?.root) assertEquals("old-root", vault.loadKeyLogPin("b.example.com")?.root, "another relay still inherits the legacy pin, not this one") } // MARK: - Extra mailboxes /** * ⚠️ **A credential per relay, not one shared.** An app password is minted * by the relay that issued it and refused everywhere else, so a single * stored credential authenticates at exactly one home and silently fails at * the rest — which reads as "the backup mailbox never has anything in it". */ @Test fun `each mailbox keeps its own credential and dial url`() { vault.saveExtraHomes(listOf( Vault.ExtraHome("a.example.com", "me", "pw-a"), Vault.ExtraHome("b.example.com", "me", "pw-b", "http://127.0.0.1:9"), )) val homes = vault.extraHomes() assertEquals(listOf("a.example.com", "b.example.com"), homes.map { it.relay }) assertEquals(listOf("pw-a", "pw-b"), homes.map { it.appPassword }) // The record names a hostname and cannot carry a port; how this device // dials that host is a separate field with a sensible default. assertEquals("https://a.example.com", homes[0].baseUrl) assertEquals("http://127.0.0.1:9", homes[1].baseUrl) } /** Dropping one takes its cursor with it, or a re-add resumes mid-inbox. */ @Test fun `forgetting a mailbox clears its cursor too`() { vault.saveExtraHomes(listOf(Vault.ExtraHome("a.example.com", "me", "pw"))) vault.setWatermarkFor("a.example.com", 900) vault.forgetExtraHome("a.example.com") assertTrue(vault.extraHomes().isEmpty()) assertEquals(0, vault.watermarkFor("a.example.com"), "a re-added mailbox would resume mid-inbox and skip everything before it") } @Test fun `an account with no extra mailboxes reads as none`() { assertTrue(vault.extraHomes().isEmpty()) assertEquals(0, vault.watermarkFor("anything.example.com")) } }