1package com.peachpasswords.sync23import org.junit.Assert.assertNotNull4import org.junit.Assert.assertNull5import org.junit.Test6import org.junit.Assert.assertEquals789101112class DeviceManifestSupportTest {13 private val master = ByteArray(32) { it.toByte() }14 private val signing = deriveSyncSigningKeypair(master, "issuer")1516 private fun validEntry(deviceId: String = "peer", pairedAt: Long = 1L) = ManifestDeviceEntry(17 deviceId = deviceId,18 deviceName = "Peer",19 deviceType = "android",20 longTermPublicKeyHex = "aa".repeat(32),21 signingPublicKeyHex = "bb".repeat(32),22 pairedAt = pairedAt,23 )2425 private fun manifestWith(issuedAt: Long, devices: List<ManifestDeviceEntry> = listOf(validEntry())) =26 buildSignedDeviceManifest(27 issuerDeviceId = "issuer",28 devices = devices,29 signingPrivateKey = signing.privateKey,30 nowMs = issuedAt,31 )3233 @Test fun rejects_issued_at_long_min_value() {34 35 36 val manifest = manifestWith(issuedAt = Long.MIN_VALUE)37 assertNull(verifyDeviceManifest(manifest, signing.publicKeyRaw, nowMs = 1_700_000_000_000L))38 }3940 @Test fun rejects_issued_at_too_old() {41 val manifest = manifestWith(issuedAt = 1L)42 assertNull(verifyDeviceManifest(manifest, signing.publicKeyRaw, nowMs = 1_700_000_000_000L))43 }4445 @Test fun rejects_issued_at_too_far_in_future() {46 val now = 1_700_000_000_000L47 48 val manifest = manifestWith(issuedAt = now + 5 * 60_000L + 1L)49 assertNull(verifyDeviceManifest(manifest, signing.publicKeyRaw, nowMs = now))50 }5152 @Test fun accepts_issued_at_within_window() {53 val now = 1_700_000_000_000L54 val manifest = manifestWith(issuedAt = now)55 assertNotNull(verifyDeviceManifest(manifest, signing.publicKeyRaw, nowMs = now))56 }5758 @Test fun rejects_oversized_device_id_string() {59 val manifest = manifestWith(60 issuedAt = 1_000L,61 devices = listOf(validEntry(deviceId = "x".repeat(10_000))),62 )63 assertNull(verifyDeviceManifest(manifest, signing.publicKeyRaw, nowMs = 1_000L))64 }6566 @Test fun caps_oversized_device_name_at_verify() {67 68 69 70 val now = 1_700_000_000_000L71 val body = DeviceManifestBody(72 manifestVersion = DEVICE_MANIFEST_VERSION,73 issuerDeviceId = "issuer",74 issuedAt = now,75 devices = listOf(validEntry().copy(deviceName = "N".repeat(200))),76 revoked = emptyList(),77 )78 val signature = signEd25519(79 signing.privateKey,80 canonicalDeviceManifestBody(body).toByteArray(Charsets.UTF_8),81 )82 val verified = verifyDeviceManifest(83 SignedDeviceManifest(body, pubkeyToHex(signature)),84 signing.publicKeyRaw,85 nowMs = now,86 )87 assertNotNull(verified)88 assertEquals("N".repeat(MAX_DEVICE_NAME_CHARS), verified!!.devices[0].deviceName)89 }9091 @Test fun caps_device_name_at_build() {92 val manifest = manifestWith(93 issuedAt = 1_000L,94 devices = listOf(validEntry().copy(deviceName = "B".repeat(200))),95 )96 assertEquals("B".repeat(MAX_DEVICE_NAME_CHARS), manifest.body.devices[0].deviceName)97 }9899 @Test fun rejects_negative_paired_at() {100 val manifest = manifestWith(101 issuedAt = 1_000L,102 devices = listOf(validEntry(pairedAt = -1L)),103 )104 assertNull(verifyDeviceManifest(manifest, signing.publicKeyRaw, nowMs = 1_000L))105 }106107 @Test fun rejects_too_many_devices() {108 val manifest = buildSignedDeviceManifest(109 issuerDeviceId = "issuer",110 devices = List(300) { validEntry(deviceId = "peer-$it") },111 signingPrivateKey = signing.privateKey,112 nowMs = 1_000L,113 )114 assertNull(verifyDeviceManifest(manifest, signing.publicKeyRaw, nowMs = 1_000L))115 }116117 @Test fun rejects_oversized_issuer_device_id() {118 val manifest = manifestWith(issuedAt = 1_000L)119 val oversized = manifest.copy(body = manifest.body.copy(issuerDeviceId = "y".repeat(2_000)))120 assertNull(verifyDeviceManifest(oversized, signing.publicKeyRaw, nowMs = 1_000L))121 }122123 @Test fun rejects_negative_revoked_at() {124 val manifest = buildSignedDeviceManifest(125 issuerDeviceId = "issuer",126 devices = emptyList(),127 signingPrivateKey = signing.privateKey,128 nowMs = 1_000L,129 revoked = listOf(130 DeviceRevocation(131 deviceId = "peer",132 longTermPublicKeyHex = "aa".repeat(32),133 revokedAt = -1L,134 revokedByDeviceId = "issuer",135 ),136 ),137 )138 assertNull(verifyDeviceManifest(manifest, signing.publicKeyRaw, nowMs = 1_000L))139 }140}