RendezvousTest.kt

4.1 KB · raw

1package com.peachpasswords.sync23import org.junit.Assert.assertEquals4import org.junit.Assert.assertNull5import org.junit.Assert.assertSame6import org.junit.Assert.assertThrows7import org.junit.Test8import java.security.SecureRandom910class RendezvousTest {11    private val handshakeHash = Rendezvous.secretFromHex(12        "0fbab8cd1782bf4b17d69beb69f5b80b0bf24d93da4924959c76ee701c32e655",13    )1415    @Test fun `matches browser rendezvous KATs`() {16        val secret = Rendezvous.deriveSecret(handshakeHash)17        assertEquals(18            "0803691c8ac7330883c0987e33cea4a171992366ce4b06b88691e84ca689773d",19            Rendezvous.bytesToHex(secret),20        )21        assertEquals(22            "9UY3j5AHnwYSApvymtY965su9n60rQOv8QZ2PZzHuKI",23            Rendezvous.deriveId(secret, 500_000),24        )25    }2627    @Test fun `uses required waiting and dialing window order`() {28        val secret = Rendezvous.deriveSecret(handshakeHash)29        val now = 500_000L * 3600 + 359930        assertEquals(31            listOf(32                Rendezvous.deriveId(secret, 500_000),33                Rendezvous.deriveId(secret, 499_999),34            ),35            Rendezvous.waitingIds(secret, now),36        )37        assertEquals(38            listOf(39                Rendezvous.deriveId(secret, 500_000),40                Rendezvous.deriveId(secret, 499_999),41                Rendezvous.deriveId(secret, 500_001),42            ),43            Rendezvous.dialingIds(secret, now),44        )45    }4647    @Test fun `opaque capabilities resolve current and previous windows only`() {48        val secretHex = "42".repeat(32)49        val peer = PairedDevice(50            deviceId = "browser-1",51            longTermPublicKeyHex = "ab".repeat(32),52            pairedAt = 1L,53            rendezvousSecretHex = secretHex,54        )55        val legacy = PairedDevice(56            deviceId = "legacy",57            longTermPublicKeyHex = "cd".repeat(32),58            pairedAt = 1L,59        )60        val secret = Rendezvous.secretFromHex(secretHex)61        val now = 500_000L * 3600 + 359962        val current = Rendezvous.deriveId(secret, 500_000)63        val previous = Rendezvous.deriveId(secret, 499_999)64        val next = Rendezvous.deriveId(secret, 500_001)6566        assertSame(peer, Rendezvous.resolvePeer(listOf(legacy, peer), current, now))67        assertSame(peer, Rendezvous.resolvePeer(listOf(legacy, peer), previous, now))68        assertNull(Rendezvous.resolvePeer(listOf(legacy, peer), next, now))69        assertNull(Rendezvous.resolvePeer(listOf(legacy, peer), "Z".repeat(43), now))70        assertNull(Rendezvous.resolvePeer(listOf(legacy), current, now))71    }7273    @Test fun `first-pair token is 128-bit base64url`() {74        val deterministic = object : SecureRandom() {75            override fun nextBytes(bytes: ByteArray) {76                bytes.indices.forEach { bytes[it] = it.toByte() }77            }78        }79        assertEquals("AAECAwQFBgcICQoLDA0ODw", Rendezvous.newPairingToken(deterministic))80    }8182    @Test fun `relay URL requires credential-free wss`() {83        assertEquals(84            "wss://relay.example.test/base",85            Rendezvous.normalizeRelayUrl("wss://relay.example.test/base/"),86        )87        assertThrows(IllegalArgumentException::class.java) {88            Rendezvous.normalizeRelayUrl("ws://relay.example.test")89        }90        assertThrows(IllegalArgumentException::class.java) {91            Rendezvous.normalizeRelayUrl("wss://user:[email protected]")92        }93    }9495    @Test fun `completed pairing persists secret and the listener relay`() {96        val device = PairedDevice(97            deviceId = "browser-1",98            deviceName = "Firefox",99            deviceType = "extension",100            longTermPublicKeyHex = "ab".repeat(32),101            pairedAt = 1L,102        )103        val bound = Rendezvous.bindPairState(104            device,105            handshakeHash,106            "wss://relay.example.test/",107        )108        assertEquals(109            "0803691c8ac7330883c0987e33cea4a171992366ce4b06b88691e84ca689773d",110            bound.rendezvousSecretHex,111        )112        assertEquals("wss://relay.example.test", bound.relayUrl)113    }114}