1package com.peachpasswords.sync23import android.content.Context4import androidx.security.crypto.EncryptedSharedPreferences5import androidx.security.crypto.MasterKey6import dagger.hilt.android.qualifiers.ApplicationContext7import kotlinx.coroutines.flow.MutableStateFlow8import kotlinx.coroutines.flow.StateFlow9import kotlinx.coroutines.flow.asStateFlow10import kotlinx.serialization.builtins.ListSerializer11import kotlinx.serialization.json.Json12import javax.inject.Inject13import javax.inject.Singleton1415@Singleton16class SyncAlertStore @Inject constructor(17 @ApplicationContext context: Context,18) : SyncAlertRecorder {19 private val masterKey = MasterKey.Builder(context)20 .setKeyScheme(MasterKey.KeyScheme.AES256_GCM)21 .build()2223 private val prefs = EncryptedSharedPreferences.create(24 context,25 PREFS_FILE,26 masterKey,27 EncryptedSharedPreferences.PrefKeyEncryptionScheme.AES256_SIV,28 EncryptedSharedPreferences.PrefValueEncryptionScheme.AES256_GCM,29 )3031 private val listSerializer = ListSerializer(SyncAlert.serializer())32 private val _alerts = MutableStateFlow(load())33 val alerts: StateFlow<List<SyncAlert>> = _alerts.asStateFlow()3435 override fun record(alerts: List<SyncAlert>) {36 val trustAlerts = alerts.filter(::isDeviceTrustAlert)37 if (trustAlerts.isEmpty()) return38 persist(boundedSyncAlerts(load(), trustAlerts))39 }4041 fun dismiss(alert: SyncAlert) {42 val current = load().toMutableList()43 val index = current.indexOf(alert)44 if (index != -1) {45 current.removeAt(index)46 persist(current)47 }48 }4950 fun clear() {51 persist(emptyList())52 }5354 private fun load(): List<SyncAlert> {55 val raw = prefs.getString(KEY_ALERTS, null) ?: return emptyList()56 return runCatching { json.decodeFromString(listSerializer, raw) }57 .getOrDefault(emptyList())58 .filter(::isDeviceTrustAlert)59 }6061 private fun persist(alerts: List<SyncAlert>) {62 prefs.edit()63 .putString(KEY_ALERTS, json.encodeToString(listSerializer, alerts))64 .apply()65 _alerts.value = alerts66 }6768 private companion object {69 const val PREFS_FILE = "peach_sync_alerts"70 const val KEY_ALERTS = "sync_alerts"71 val json = Json { encodeDefaults = true; ignoreUnknownKeys = true }72 }73}