PairingInvitationTest.kt

3.3 KB · raw

1package com.peachpasswords.sync23import org.junit.Assert.assertEquals4import org.junit.Assert.assertNotNull5import org.junit.Assert.assertNull6import org.junit.Test78class PairingInvitationTest {9    private val token = "AAECAwQFBgcICQoLDA0ODw"10    private val relay = "wss://relay.peachpasswords.com"11    private val kat =12        "peach-pair-v1:eyJyZWxheSI6IndzczovL3JlbGF5LnBlYWNocGFzc3dvcmRzLmNvbSIsInRva2VuIjoiQUFFQ0F3UUZCZ2NJQ1FvTERBME9EdyIsInZhdWx0IjoicG9wdWxhdGVkIn0"13    private val emptyKat =14        "peach-pair-v1:eyJyZWxheSI6IndzczovL3JlbGF5LnBlYWNocGFzc3dvcmRzLmNvbSIsInRva2VuIjoiQUFFQ0F3UUZCZ2NJQ1FvTERBME9EdyIsInZhdWx0IjoiZW1wdHkifQ"1516    @Test fun `matches browser invitation KAT with default populated vault`() {17        assertEquals(kat, createPairingInvitation("$relay/", token))18        val parsed = parsePairingInvitation(kat)19        assertEquals(PairingInvitation(relay, token, VaultStatus.POPULATED), parsed)20        assertEquals("$relay/r/$token", parsed!!.roomUrl())21    }2223    @Test fun `empty invitation round-trips as source role`() {24        assertEquals(emptyKat, createPairingInvitation(relay, token, VaultStatus.EMPTY))25        val parsed = parsePairingInvitation(emptyKat)26        assertEquals(PairingInvitation(relay, token, VaultStatus.EMPTY), parsed)27    }2829    @Test fun `explicit populated invitation round-trips as receiver role`() {30        val invitation = createPairingInvitation(relay, token, VaultStatus.POPULATED)31        val parsed = parsePairingInvitation(invitation)32        assertEquals(VaultStatus.POPULATED, parsed?.vaultStatus)33    }3435    @Test fun `missing vault field defaults to populated for historical compatibility`() {36        val older = raw("""{"relay":"$relay","token":"$token"}""")37        val parsed = parsePairingInvitation(older)38        assertEquals(VaultStatus.POPULATED, parsed?.vaultStatus)39        assertEquals(PairingInvitation(relay, token), parsed)40    }4142    @Test fun `unknown vault value defaults to populated`() {43        val weird = raw("""{"relay":"$relay","token":"$token","vault":"maybe"}""")44        val parsed = parsePairingInvitation(weird)45        assertEquals(VaultStatus.POPULATED, parsed?.vaultStatus)46    }4748    @Test fun `vaultStatus on the parsed invitation drives the adoption flow`() {49        val empty = parsePairingInvitation(emptyKat)50        val populated = parsePairingInvitation(kat)51        val legacy = parsePairingInvitation(raw("""{"relay":"$relay","token":"$token"}"""))52        assertNotNull(empty)53        assertNotNull(populated)54        assertNotNull(legacy)55        assertEquals(VaultStatus.EMPTY, empty!!.vaultStatus)56        assertEquals(VaultStatus.POPULATED, populated!!.vaultStatus)57        assertEquals(VaultStatus.POPULATED, legacy!!.vaultStatus)58    }5960    @Test fun `rejects malformed insecure and short-token invitations`() {61        assertNull(parsePairingInvitation("not-an-invitation"))62        assertNull(parsePairingInvitation("peach-pair-v1:%%%"))63        assertNull(parsePairingInvitation(raw("""{"relay":"ws://relay.test","token":"$token"}""")))64        assertNull(parsePairingInvitation(raw("""{"relay":"$relay","token":"short"}""")))65    }6667    private fun raw(json: String): String =68        "peach-pair-v1:" + java.util.Base64.getUrlEncoder().withoutPadding()69            .encodeToString(json.toByteArray())70}