package io.flamenet.e2e import kotlin.test.Test import kotlin.test.assertEquals import kotlin.test.assertNull import kotlin.test.assertTrue /** * Parsing an address, and refusing everything that is nearly one. * * 🔴 **This runs on input nobody authenticated.** An address arrives typed, or * pasted, or scanned from a code somebody else printed — and, worst of all, * from inside a sealed envelope written by a stranger on another relay. So the * refusals matter more than the successes: accepting `fnid@https://x/y` would * let a message point this client at a path on a host of the sender's choosing. * * ⚠️ The cases here deliberately mirror the Swift suite one for one. Two * implementations that disagree about which strings are addresses open two * threads for one person on one side and none on the other, and nothing about * either engine's own tests would show it. */ class ContactCardTest { @Test fun `a bare address with no scheme is accepted`() { val card = ContactCard.decode("fn1abc@relay1.flamenet.io") assertEquals("fn1abc", card?.fnid) assertEquals("relay1.flamenet.io", card?.relay) assertNull(card?.deliveryKey, "no key means it cannot be sealed, and that is knowable") } @Test fun `the scheme is stripped and the host lowercased`() { val card = ContactCard.decode(" FLAMENET:fn1abc@Relay1.Flamenet.IO ") assertEquals("fn1abc", card?.fnid) assertEquals("relay1.flamenet.io", card?.relay) assertEquals("fn1abc@relay1.flamenet.io", card?.address) } @Test fun `what it encodes parses back to the same address`() { val card = ContactCard("fn1abc", "relay1.flamenet.io") assertEquals("flamenet:fn1abc@relay1.flamenet.io", card.encoded) assertEquals(card.address, ContactCard.decode(card.encoded)?.address) } /** * ⚠️ Kept only so an older card still parses. Nothing reads it and nothing * should start to: sealing uses the recipient DEVICE's key, which the * remote directory returns, and the federated send carries no delivery key * at all. */ @Test fun `an older card carrying a delivery key still parses`() { val card = ContactCard.decode("flamenet:fn1abc@relay1.flamenet.io?k=" + "A".repeat(44)) assertEquals("fn1abc", card?.fnid) assertEquals("relay1.flamenet.io", card?.relay) assertEquals("A".repeat(44), card?.deliveryKey) // And it is NOT re-emitted, because publishing a secret-shaped thing // for nothing doubles the length of every address. assertTrue("?" !in card!!.encoded, card.encoded) } /** * 🔴 A relay is a hostname. Accepting a URL here would let a card — or a * message from a stranger — point this client at a path on somebody else's * host. */ @Test fun `a relay that is a URL is refused`() { assertNull(ContactCard.decode("fn1@https://evil.example.com/path")) assertNull(ContactCard.decode("fn1@evil.example.com/path")) assertNull(ContactCard.decode("fn1@evil.example.com:8443")) } @Test fun `the nearly right is refused`() { assertNull(ContactCard.decode("")) assertNull(ContactCard.decode("fn1abc"), "no relay at all") assertNull(ContactCard.decode("@relay1.flamenet.io"), "no address") assertNull(ContactCard.decode("fn1abc@"), "no relay") assertNull(ContactCard.decode("fn1abc@localhost"), "a hostname needs a dot") } /** * ⚠️ A second `@` means this is not one address. Splitting on the first * would silently address a different host than the string names. */ @Test fun `two at signs is not one address`() { assertNull(ContactCard.decode("fn1abc@a@b.example.com")) } /** * 🔴 Two spellings of one address would open two threads for one person, so * everything that files a message goes through the same normaliser. */ @Test fun `canonical gives one spelling for one address`() { val spellings = listOf( "fn1abc@relay1.flamenet.io", "flamenet:fn1abc@relay1.flamenet.io", " fn1abc@RELAY1.Flamenet.io ", "flamenet:fn1abc@relay1.flamenet.io?k=" + "A".repeat(44), ) val canonical = spellings.map { ContactCard.canonical(it) }.toSet() assertEquals(setOf("fn1abc@relay1.flamenet.io"), canonical, "got $canonical") } @Test fun `canonical refuses what decode refuses`() { for (bad in listOf("", "fn1abc", "fn1abc@localhost", "fn1@evil.example.com/x")) { assertNull(ContactCard.canonical(bad), "accepted $bad") } } }