SyncAlertStore.kt

2.4 KB · raw

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}