1package com.peachpasswords.sync23import org.junit.Assert.assertNotNull4import org.junit.Assert.assertNull5import org.junit.Test67891011class DeviceManifestSupportTest {12 private val master = ByteArray(32) { it.toByte() }13 private val signing = deriveSyncSigningKeypair(master, "issuer")1415 private fun validEntry(deviceId: String = "peer", pairedAt: Long = 1L) = ManifestDeviceEntry(16 deviceId = deviceId,17 deviceName = "Peer",18 deviceType = "android",19 longTermPublicKeyHex = "aa".repeat(32),20 signingPublicKeyHex = "bb".repeat(32),21 pairedAt = pairedAt,22 )2324 private fun manifestWith(issuedAt: Long, devices: List<ManifestDeviceEntry> = listOf(validEntry())) =25 buildSignedDeviceManifest(26 issuerDeviceId = "issuer",27 devices = devices,28 signingPrivateKey = signing.privateKey,29 nowMs = issuedAt,30 )3132 @Test fun rejects_issued_at_long_min_value() {33 34 35 val manifest = manifestWith(issuedAt = Long.MIN_VALUE)36 assertNull(verifyDeviceManifest(manifest, signing.publicKeyRaw, nowMs = 1_700_000_000_000L))37 }3839 @Test fun rejects_issued_at_too_old() {40 val manifest = manifestWith(issuedAt = 1L)41 assertNull(verifyDeviceManifest(manifest, signing.publicKeyRaw, nowMs = 1_700_000_000_000L))42 }4344 @Test fun rejects_issued_at_too_far_in_future() {45 val now = 1_700_000_000_000L46 47 val manifest = manifestWith(issuedAt = now + 5 * 60_000L + 1L)48 assertNull(verifyDeviceManifest(manifest, signing.publicKeyRaw, nowMs = now))49 }5051 @Test fun accepts_issued_at_within_window() {52 val now = 1_700_000_000_000L53 val manifest = manifestWith(issuedAt = now)54 assertNotNull(verifyDeviceManifest(manifest, signing.publicKeyRaw, nowMs = now))55 }5657 @Test fun rejects_oversized_device_id_string() {58 val manifest = manifestWith(59 issuedAt = 1_000L,60 devices = listOf(validEntry(deviceId = "x".repeat(10_000))),61 )62 assertNull(verifyDeviceManifest(manifest, signing.publicKeyRaw, nowMs = 1_000L))63 }6465 @Test fun rejects_negative_paired_at() {66 val manifest = manifestWith(67 issuedAt = 1_000L,68 devices = listOf(validEntry(pairedAt = -1L)),69 )70 assertNull(verifyDeviceManifest(manifest, signing.publicKeyRaw, nowMs = 1_000L))71 }7273 @Test fun rejects_too_many_devices() {74 val manifest = buildSignedDeviceManifest(75 issuerDeviceId = "issuer",76 devices = List(300) { validEntry(deviceId = "peer-$it") },77 signingPrivateKey = signing.privateKey,78 nowMs = 1_000L,79 )80 assertNull(verifyDeviceManifest(manifest, signing.publicKeyRaw, nowMs = 1_000L))81 }8283 @Test fun rejects_oversized_issuer_device_id() {84 val manifest = manifestWith(issuedAt = 1_000L)85 val oversized = manifest.copy(body = manifest.body.copy(issuerDeviceId = "y".repeat(2_000)))86 assertNull(verifyDeviceManifest(oversized, signing.publicKeyRaw, nowMs = 1_000L))87 }8889 @Test fun rejects_negative_revoked_at() {90 val manifest = buildSignedDeviceManifest(91 issuerDeviceId = "issuer",92 devices = emptyList(),93 signingPrivateKey = signing.privateKey,94 nowMs = 1_000L,95 revoked = listOf(96 DeviceRevocation(97 deviceId = "peer",98 longTermPublicKeyHex = "aa".repeat(32),99 revokedAt = -1L,100 revokedByDeviceId = "issuer",101 ),102 ),103 )104 assertNull(verifyDeviceManifest(manifest, signing.publicKeyRaw, nowMs = 1_000L))105 }106}