LocalIdentityRecordTest.kt

4.7 KB · raw

1package com.peachpasswords.sync23import org.junit.Assert.assertEquals4import org.junit.Assert.assertTrue5import org.junit.Test67/**8 * Frozen local-identity schema (campaign task 2.1): round trip, legacy9 * completion, and every malformed-shape rejection. These run on the JVM because10 * the codec is storage-agnostic; `DeviceIdentity` only adapts it to11 * EncryptedSharedPreferences.12 */13class LocalIdentityRecordTest {1415    @Test fun round_trips_every_frozen_field() {16        val credentials = randomLocalIdentityCredentials("device-a")17        val fields = identityRecordFields(credentials, createdAt = 1_700_000_000_000L)1819        val decoded = readIdentityRecord(fields)2021        assertTrue(decoded is IdentityRecord.Current)22        val current = decoded as IdentityRecord.Current23        assertEquals("device-a", current.credentials.deviceId)24        assertTrue(current.credentials.x25519PrivateKey.contentEquals(credentials.x25519PrivateKey))25        assertTrue(current.credentials.x25519PublicKey.contentEquals(credentials.x25519PublicKey))26        assertTrue(current.credentials.ed25519Seed.contentEquals(credentials.ed25519Seed))27        assertTrue(current.credentials.ed25519PublicKey.contentEquals(credentials.ed25519PublicKey))28        assertEquals(1_700_000_000_000L, current.createdAt)29    }3031    @Test fun no_stored_fields_is_absent() {32        assertEquals(IdentityRecord.Absent, readIdentityRecord(emptyMap()))33    }3435    @Test fun legacy_random_record_completes_without_changing_the_identity() {36        val credentials = randomLocalIdentityCredentials("legacy-id")37        val fields = mapOf<String, Any?>(38            FIELD_VERSION to LOCAL_IDENTITY_RECORD_VERSION_LEGACY_RANDOM,39            FIELD_DEVICE_ID to credentials.deviceId,40            FIELD_X25519_PRIVATE to pubkeyToHex(credentials.x25519PrivateKey),41            FIELD_ED25519_SEED to pubkeyToHex(credentials.ed25519Seed),42        )4344        val decoded = readIdentityRecord(fields)4546        assertTrue(decoded is IdentityRecord.LegacyRandom)47        val legacy = decoded as IdentityRecord.LegacyRandom48        assertEquals("legacy-id", legacy.credentials.deviceId)49        assertTrue(legacy.credentials.x25519PrivateKey.contentEquals(credentials.x25519PrivateKey))50        assertTrue(legacy.credentials.ed25519Seed.contentEquals(credentials.ed25519Seed))51    }5253    @Test fun unknown_version_is_invalid() {54        val credentials = randomLocalIdentityCredentials("device-a")55        val fields = identityRecordFields(credentials, 1L) + (FIELD_VERSION to 99)56        assertEquals(IdentityRecord.Invalid, readIdentityRecord(fields))57    }5859    @Test fun stored_public_key_that_does_not_match_the_private_key_is_invalid() {60        val credentials = randomLocalIdentityCredentials("device-a")61        val fields = identityRecordFields(credentials, 1L) + (FIELD_X25519_PUBLIC to "aa".repeat(32))62        assertEquals(IdentityRecord.Invalid, readIdentityRecord(fields))63    }6465    @Test fun missing_creation_time_is_invalid() {66        val credentials = randomLocalIdentityCredentials("device-a")67        val fields = identityRecordFields(credentials, 1L) - FIELD_CREATED_AT68        assertEquals(IdentityRecord.Invalid, readIdentityRecord(fields))69    }7071    @Test fun missing_stored_public_value_is_invalid() {72        val credentials = randomLocalIdentityCredentials("device-a")73        val fields = identityRecordFields(credentials, 1L) - FIELD_ED25519_PUBLIC74        assertEquals(IdentityRecord.Invalid, readIdentityRecord(fields))75    }7677    @Test fun private_material_without_a_version_is_invalid() {78        val credentials = randomLocalIdentityCredentials("device-a")79        val fields = identityRecordFields(credentials, 1L) - FIELD_VERSION80        assertEquals(IdentityRecord.Invalid, readIdentityRecord(fields))81    }8283    @Test fun partial_private_material_is_invalid() {84        val fields = mapOf<String, Any?>(85            FIELD_VERSION to LOCAL_IDENTITY_RECORD_VERSION,86            FIELD_DEVICE_ID to "device-a",87            FIELD_ED25519_SEED to "22".repeat(32),88        )89        assertEquals(IdentityRecord.Invalid, readIdentityRecord(fields))90    }9192    @Test fun malformed_private_hex_is_invalid() {93        val fields = mapOf<String, Any?>(94            FIELD_VERSION to LOCAL_IDENTITY_RECORD_VERSION,95            FIELD_DEVICE_ID to "device-a",96            FIELD_X25519_PRIVATE to "not-hex",97            FIELD_ED25519_SEED to "22".repeat(32),98        )99        assertEquals(IdentityRecord.Invalid, readIdentityRecord(fields))100    }101102    @Test fun blank_device_id_is_invalid() {103        val credentials = randomLocalIdentityCredentials("device-a")104        val fields = identityRecordFields(credentials, 1L) + (FIELD_DEVICE_ID to "")105        assertEquals(IdentityRecord.Invalid, readIdentityRecord(fields))106    }107}