1package com.peachpasswords.sync23import android.content.Context4import java.util.UUID56private const val DEVICE_ID_KEY = "peach_chirp_device_id"7private const val DEVICE_NAME_KEY = "peach_chirp_device_name"8private const val PREFS_FILE = "peach_chirp_identity"910data class LocalChirpIdentity(11 val deviceId: String,12 val deviceName: String,13 val deviceType: DeviceType,14 val longTermPublicKeyHex: String,15 val signingPublicKeyHex: String,16 val wsPort: Int? = null,17 1819202122 val license: String? = null,23)2425fun getOrCreateDeviceId(context: Context): String {26 val prefs = context.getSharedPreferences(PREFS_FILE, Context.MODE_PRIVATE)27 val current = prefs.getString(DEVICE_ID_KEY, null)28 if (!current.isNullOrEmpty()) return current29 val fresh = UUID.randomUUID().toString()30 prefs.edit().putString(DEVICE_ID_KEY, fresh).apply()31 return fresh32}3334fun getDeviceName(context: Context): String {35 val prefs = context.getSharedPreferences(PREFS_FILE, Context.MODE_PRIVATE)36 return prefs.getString(DEVICE_NAME_KEY, null).orEmpty().ifBlank { defaultDeviceName() }37}3839fun setDeviceName(context: Context, name: String) {40 val trimmed = name.trim()41 require(trimmed.isNotEmpty()) { "device name must not be empty" }42 require(trimmed.length <= 64) { "device name must be 64 chars or fewer" }43 context.getSharedPreferences(PREFS_FILE, Context.MODE_PRIVATE)44 .edit()45 .putString(DEVICE_NAME_KEY, trimmed)46 .apply()47}4849fun buildLocalIdentity(context: Context, masterKey: ByteArray): LocalChirpIdentity {50 val deviceId = getOrCreateDeviceId(context)51 val deviceName = getDeviceName(context)52 val kp = deriveSyncIdentityKeypair(masterKey, deviceId)53 val signing = deriveSyncSigningKeypair(masterKey, deviceId)54 return LocalChirpIdentity(55 deviceId = deviceId,56 deviceName = deviceName,57 deviceType = extensionDeviceType(),58 longTermPublicKeyHex = pubkeyToHex(kp.publicKey),59 signingPublicKeyHex = pubkeyToHex(signing.publicKeyRaw),60 61 62 63 wsPort = SyncReconnectListener.SYNC_PORT,64 )65}6667fun deriveLocalSyncKeypair(masterKey: ByteArray, deviceId: String): SyncIdentityKeypair {68 return deriveSyncIdentityKeypair(masterKey, deviceId)69}7071private fun defaultDeviceName(): String {72 return "Android"73}7475private fun extensionDeviceType(): DeviceType {76 return DeviceType.ANDROID77}