chore: refactor the internal storage layer (#40)
Reviewed-on: #40
This commit was merged in pull request #40.
This commit is contained in:
14
shared/src/commonMain/kotlin/su/reya/coop/AppStorage.kt
Normal file
14
shared/src/commonMain/kotlin/su/reya/coop/AppStorage.kt
Normal file
@@ -0,0 +1,14 @@
|
||||
package su.reya.coop
|
||||
|
||||
interface AppStorage {
|
||||
// Plain text storage
|
||||
suspend fun get(key: String): String?
|
||||
suspend fun set(key: String, value: String)
|
||||
|
||||
// Encrypted storage
|
||||
suspend fun getSecret(key: String): String?
|
||||
suspend fun setSecret(key: String, value: String)
|
||||
|
||||
suspend fun clear(key: String)
|
||||
suspend fun has(key: String): Boolean
|
||||
}
|
||||
@@ -1,8 +0,0 @@
|
||||
package su.reya.coop.storage
|
||||
|
||||
interface SecretStorage {
|
||||
suspend fun get(key: String): String?
|
||||
suspend fun set(key: String, value: String)
|
||||
suspend fun clear(key: String)
|
||||
suspend fun has(key: String): Boolean
|
||||
}
|
||||
@@ -12,12 +12,12 @@ import rust.nostr.sdk.Keys
|
||||
import rust.nostr.sdk.NostrConnect
|
||||
import rust.nostr.sdk.NostrConnectUri
|
||||
import rust.nostr.sdk.PublicKey
|
||||
import su.reya.coop.AppStorage
|
||||
import su.reya.coop.nostr.ExternalSignerHandler
|
||||
import su.reya.coop.nostr.ExternalSignerProxy
|
||||
import su.reya.coop.nostr.Nostr
|
||||
import su.reya.coop.nostr.SignerPermissions
|
||||
import su.reya.coop.repository.MediaRepository
|
||||
import su.reya.coop.storage.SecretStorage
|
||||
import kotlin.time.Duration.Companion.seconds
|
||||
|
||||
data class AuthState(
|
||||
@@ -27,7 +27,7 @@ data class AuthState(
|
||||
|
||||
class AuthViewModel(
|
||||
private val nostr: Nostr,
|
||||
private val secretStore: SecretStorage,
|
||||
private val storage: AppStorage,
|
||||
private val externalSignerHandler: ExternalSignerHandler? = null,
|
||||
) : BaseViewModel() {
|
||||
private val mediaRepository = MediaRepository()
|
||||
@@ -51,7 +51,7 @@ class AuthViewModel(
|
||||
|
||||
private fun checkNotificationBannerDismissedStatus() {
|
||||
viewModelScope.launch {
|
||||
val dismissed = secretStore.get(KEY_BANNER_DISMISSED) == "true"
|
||||
val dismissed = storage.get(KEY_BANNER_DISMISSED) == "true"
|
||||
_state.update { it.copy(isNotificationBannerDismissed = dismissed) }
|
||||
}
|
||||
}
|
||||
@@ -60,7 +60,7 @@ class AuthViewModel(
|
||||
viewModelScope.launch {
|
||||
try {
|
||||
val secret = withTimeoutOrNull(5.seconds) {
|
||||
secretStore.get(KEY_USER_SIGNER)
|
||||
storage.getSecret(KEY_USER_SIGNER)
|
||||
}
|
||||
|
||||
if (secret == null) {
|
||||
@@ -94,8 +94,8 @@ class AuthViewModel(
|
||||
showError("Logout encountered an error: ${e.message}")
|
||||
} finally {
|
||||
// Clear credentials from persistent storage
|
||||
secretStore.clear(KEY_USER_SIGNER)
|
||||
secretStore.clear(KEY_BANNER_DISMISSED)
|
||||
storage.clear(KEY_USER_SIGNER)
|
||||
storage.clear(KEY_BANNER_DISMISSED)
|
||||
// Call cleanup callback (e.g. to reset other ViewModels)
|
||||
onLogout()
|
||||
// Reset local states
|
||||
@@ -106,18 +106,18 @@ class AuthViewModel(
|
||||
|
||||
fun dismissNotificationBanner() {
|
||||
viewModelScope.launch {
|
||||
secretStore.set(KEY_BANNER_DISMISSED, "true")
|
||||
storage.set(KEY_BANNER_DISMISSED, "true")
|
||||
_state.update { it.copy(isNotificationBannerDismissed = true) }
|
||||
}
|
||||
}
|
||||
|
||||
private suspend fun getOrInitAppKeys(): Keys {
|
||||
val secret = secretStore.get(KEY_APP_KEYS)
|
||||
val secret = storage.getSecret(KEY_APP_KEYS)
|
||||
// If app keys are already stored, use them
|
||||
if (secret != null) return Keys.parse(secret)
|
||||
// Generate new app keys and save to the secret storage
|
||||
val keys = Keys.generate()
|
||||
secretStore.set(KEY_APP_KEYS, keys.secretKey().toBech32())
|
||||
storage.setSecret(KEY_APP_KEYS, keys.secretKey().toBech32())
|
||||
return keys
|
||||
}
|
||||
|
||||
@@ -166,7 +166,7 @@ class AuthViewModel(
|
||||
// Update signer
|
||||
nostr.setSigner(signer)
|
||||
// Persist the secret in the secret storage
|
||||
secretStore.set(KEY_USER_SIGNER, decryptedSecret ?: secret)
|
||||
storage.setSecret(KEY_USER_SIGNER, decryptedSecret ?: secret)
|
||||
// Update local states
|
||||
_state.update { it.copy(signerRequired = false) }
|
||||
}
|
||||
@@ -195,7 +195,7 @@ class AuthViewModel(
|
||||
// Update signer
|
||||
nostr.setSigner(signer)
|
||||
// Store the signer in the secret storage
|
||||
secretStore.set(KEY_USER_SIGNER, "nip55://${result.packageName}/${result.pubkey.toHex()}")
|
||||
storage.setSecret(KEY_USER_SIGNER, "nip55://${result.packageName}/${result.pubkey.toHex()}")
|
||||
// Update local states
|
||||
_state.update { it.copy(signerRequired = false) }
|
||||
}
|
||||
@@ -218,7 +218,7 @@ class AuthViewModel(
|
||||
// Create identity
|
||||
nostr.profiles.createIdentity(keys = keys, name = name, bio = bio, picture = avatarUrl)
|
||||
// Persist the secret in the secret storage
|
||||
secretStore.set(KEY_USER_SIGNER, secret)
|
||||
storage.setSecret(KEY_USER_SIGNER, secret)
|
||||
// Update local states
|
||||
_state.update { it.copy(signerRequired = false) }
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user