1package com.peachpasswords.sync23import android.content.Context4import java.util.UUID5678910private const val DEVICE_ID_KEY = "peach_chirp_device_id"11private const val DEVICE_NAME_KEY = "peach_chirp_device_name"12private const val PREFS_FILE = "peach_chirp_identity"1314data class LocalDeviceIdentity(15 val deviceId: String,16 val deviceName: String,17 val deviceType: DeviceType,18 val longTermPublicKeyHex: String,19 val signingPublicKeyHex: String,20 val wsPort: Int? = null,21 val relayUrl: String = Rendezvous.DEFAULT_RELAY_URL,22 2324252627 val license: String? = null,28)2930fun getOrCreateDeviceId(context: Context): String {31 val prefs = context.getSharedPreferences(PREFS_FILE, Context.MODE_PRIVATE)32 val current = prefs.getString(DEVICE_ID_KEY, null)33 if (!current.isNullOrEmpty()) return current34 val fresh = UUID.randomUUID().toString()35 prefs.edit().putString(DEVICE_ID_KEY, fresh).apply()36 return fresh37}3839fun getDeviceName(context: Context): String {40 val prefs = context.getSharedPreferences(PREFS_FILE, Context.MODE_PRIVATE)41 return prefs.getString(DEVICE_NAME_KEY, null).orEmpty().ifBlank { defaultDeviceName() }42}4344fun setDeviceName(context: Context, name: String) {45 val trimmed = name.trim()46 require(trimmed.isNotEmpty()) { "device name must not be empty" }47 require(trimmed.length <= 64) { "device name must be 64 chars or fewer" }48 context.getSharedPreferences(PREFS_FILE, Context.MODE_PRIVATE)49 .edit()50 .putString(DEVICE_NAME_KEY, trimmed)51 .apply()52}5354fun clearDeviceIdentity(context: Context) {55 context.getSharedPreferences(PREFS_FILE, Context.MODE_PRIVATE)56 .edit()57 .clear()58 .apply()59}6061fun buildLocalIdentity(context: Context, masterKey: ByteArray): LocalDeviceIdentity {62 val deviceId = getOrCreateDeviceId(context)63 val deviceName = getDeviceName(context)64 val kp = deriveSyncIdentityKeypair(masterKey, deviceId)65 val signing = deriveSyncSigningKeypair(masterKey, deviceId)66 return LocalDeviceIdentity(67 deviceId = deviceId,68 deviceName = deviceName,69 deviceType = extensionDeviceType(),70 longTermPublicKeyHex = pubkeyToHex(kp.publicKey),71 signingPublicKeyHex = pubkeyToHex(signing.publicKeyRaw),72 73 74 wsPort = null,75 relayUrl = RelaySettingsStore.readRelayUrl(context),76 )77}7879fun deriveLocalSyncKeypair(masterKey: ByteArray, deviceId: String): SyncIdentityKeypair {80 return deriveSyncIdentityKeypair(masterKey, deviceId)81}8283private fun defaultDeviceName(): String {84 return "Android"85}8687private fun extensionDeviceType(): DeviceType {88 return DeviceType.ANDROID89}