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 buildLocalIdentity(context: Context, masterKey: ByteArray): LocalDeviceIdentity {55 val deviceId = getOrCreateDeviceId(context)56 val deviceName = getDeviceName(context)57 val kp = deriveSyncIdentityKeypair(masterKey, deviceId)58 val signing = deriveSyncSigningKeypair(masterKey, deviceId)59 return LocalDeviceIdentity(60 deviceId = deviceId,61 deviceName = deviceName,62 deviceType = extensionDeviceType(),63 longTermPublicKeyHex = pubkeyToHex(kp.publicKey),64 signingPublicKeyHex = pubkeyToHex(signing.publicKeyRaw),65 66 67 wsPort = null,68 relayUrl = RelaySettingsStore.readRelayUrl(context),69 )70}7172fun deriveLocalSyncKeypair(masterKey: ByteArray, deviceId: String): SyncIdentityKeypair {73 return deriveSyncIdentityKeypair(masterKey, deviceId)74}7576private fun defaultDeviceName(): String {77 return "Android"78}7980private fun extensionDeviceType(): DeviceType {81 return DeviceType.ANDROID82}