1package com.peachpasswords.sync23import org.junit.Assert.assertEquals4import org.junit.Assert.assertThrows5import org.junit.Test6import java.security.SecureRandom78class RendezvousTest {9 private val handshakeHash = Rendezvous.secretFromHex(10 "0fbab8cd1782bf4b17d69beb69f5b80b0bf24d93da4924959c76ee701c32e655",11 )1213 @Test fun `matches browser rendezvous KATs`() {14 val secret = Rendezvous.deriveSecret(handshakeHash)15 assertEquals(16 "0803691c8ac7330883c0987e33cea4a171992366ce4b06b88691e84ca689773d",17 Rendezvous.bytesToHex(secret),18 )19 assertEquals(20 "9UY3j5AHnwYSApvymtY965su9n60rQOv8QZ2PZzHuKI",21 Rendezvous.deriveId(secret, 500_000),22 )23 }2425 @Test fun `uses required waiting and dialing window order`() {26 val secret = Rendezvous.deriveSecret(handshakeHash)27 val now = 500_000L * 3600 + 359928 assertEquals(29 listOf(30 Rendezvous.deriveId(secret, 500_000),31 Rendezvous.deriveId(secret, 499_999),32 ),33 Rendezvous.waitingIds(secret, now),34 )35 assertEquals(36 listOf(37 Rendezvous.deriveId(secret, 500_000),38 Rendezvous.deriveId(secret, 499_999),39 Rendezvous.deriveId(secret, 500_001),40 ),41 Rendezvous.dialingIds(secret, now),42 )43 }4445 @Test fun `first-pair token is 128-bit base64url`() {46 val deterministic = object : SecureRandom() {47 override fun nextBytes(bytes: ByteArray) {48 bytes.indices.forEach { bytes[it] = it.toByte() }49 }50 }51 assertEquals("AAECAwQFBgcICQoLDA0ODw", Rendezvous.newPairingToken(deterministic))52 }5354 @Test fun `relay URL requires credential-free wss`() {55 assertEquals(56 "wss://relay.example.test/base",57 Rendezvous.normalizeRelayUrl("wss://relay.example.test/base/"),58 )59 assertThrows(IllegalArgumentException::class.java) {60 Rendezvous.normalizeRelayUrl("ws://relay.example.test")61 }62 assertThrows(IllegalArgumentException::class.java) {63 Rendezvous.normalizeRelayUrl("wss://user:[email protected]")64 }65 }6667 @Test fun `completed pairing persists secret and the listener relay`() {68 val device = PairedDevice(69 deviceId = "browser-1",70 deviceName = "Firefox",71 deviceType = "extension",72 longTermPublicKeyHex = "ab".repeat(32),73 pairedAt = 1L,74 )75 val bound = Rendezvous.bindPairState(76 device,77 handshakeHash,78 "wss://relay.example.test/",79 )80 assertEquals(81 "0803691c8ac7330883c0987e33cea4a171992366ce4b06b88691e84ca689773d",82 bound.rendezvousSecretHex,83 )84 assertEquals("wss://relay.example.test", bound.relayUrl)85 }86}