mirror of
https://github.com/vitorpamplona/amethyst.git
synced 2025-04-08 20:08:06 +02:00
Migration from old to new preferences
This commit is contained in:
parent
992796a7bf
commit
269197a59d
@ -6,13 +6,17 @@ import androidx.security.crypto.MasterKey
|
||||
object EncryptedStorage {
|
||||
private const val PREFERENCES_NAME = "secret_keeper"
|
||||
|
||||
fun prefsFileName(npub: String? = null): String {
|
||||
return if (npub == null) PREFERENCES_NAME else "${PREFERENCES_NAME}_$npub"
|
||||
}
|
||||
|
||||
fun preferences(npub: String? = null): EncryptedSharedPreferences {
|
||||
val context = Amethyst.instance
|
||||
val masterKey: MasterKey = MasterKey.Builder(context, MasterKey.DEFAULT_MASTER_KEY_ALIAS)
|
||||
.setKeyScheme(MasterKey.KeyScheme.AES256_GCM)
|
||||
.build()
|
||||
|
||||
val preferencesName = if (npub == null) PREFERENCES_NAME else "${PREFERENCES_NAME}_$npub"
|
||||
val preferencesName = prefsFileName(npub)
|
||||
|
||||
return EncryptedSharedPreferences.create(
|
||||
context,
|
||||
|
@ -11,17 +11,25 @@ import com.vitorpamplona.amethyst.model.toByteArray
|
||||
import com.vitorpamplona.amethyst.service.model.ContactListEvent
|
||||
import com.vitorpamplona.amethyst.service.model.Event
|
||||
import com.vitorpamplona.amethyst.service.model.Event.Companion.getRefinedEvent
|
||||
import fr.acinq.secp256k1.Hex
|
||||
import nostr.postr.Persona
|
||||
import nostr.postr.toHex
|
||||
import nostr.postr.toNpub
|
||||
import java.io.File
|
||||
import java.util.Locale
|
||||
|
||||
// Release mode (!BuildConfig.DEBUG) always uses encrypted preferences
|
||||
// To use plaintext SharedPreferences for debugging, set this to true
|
||||
// It will only apply in Debug builds
|
||||
const val DEBUG_PLAINTEXT_PREFERENCES = true
|
||||
private const val DEBUG_PLAINTEXT_PREFERENCES = false
|
||||
private const val OLD_PREFS_FILENAME = "secret_keeper"
|
||||
|
||||
data class AccountInfo(val npub: String, val current: Boolean, val displayName: String?, val profilePicture: String?)
|
||||
data class AccountInfo(
|
||||
val npub: String,
|
||||
val current: Boolean,
|
||||
val displayName: String?,
|
||||
val profilePicture: String?
|
||||
)
|
||||
|
||||
private object PrefKeys {
|
||||
const val CURRENT_ACCOUNT = "currently_logged_in_account"
|
||||
@ -57,6 +65,9 @@ object LocalPreferences {
|
||||
private val savedAccounts: Set<String>
|
||||
get() = encryptedPreferences().getStringSet(PrefKeys.SAVED_ACCOUNTS, null) ?: setOf()
|
||||
|
||||
private val prefsDirPath: String
|
||||
get() = "${Amethyst.instance.filesDir.parent}/shared_prefs/"
|
||||
|
||||
private fun addAccount(npub: String) {
|
||||
val accounts = savedAccounts.toMutableSet()
|
||||
accounts.add(npub)
|
||||
@ -66,6 +77,12 @@ object LocalPreferences {
|
||||
}.apply()
|
||||
}
|
||||
|
||||
private fun setCurrentAccount(account: Account) {
|
||||
val npub = account.userProfile().pubkeyNpub()
|
||||
currentAccount = npub
|
||||
addAccount(npub)
|
||||
}
|
||||
|
||||
/**
|
||||
* Removes the account from the app level shared preferences
|
||||
*/
|
||||
@ -82,8 +99,7 @@ object LocalPreferences {
|
||||
* Deletes the npub-specific shared preference file
|
||||
*/
|
||||
private fun deleteUserPreferenceFile(npub: String) {
|
||||
val context = Amethyst.instance
|
||||
val prefsDir = File("${context.filesDir.parent}/shared_prefs/")
|
||||
val prefsDir = File(prefsDirPath)
|
||||
prefsDir.list()?.forEach {
|
||||
if (it.contains(npub)) {
|
||||
File(prefsDir, it).delete()
|
||||
@ -93,7 +109,7 @@ object LocalPreferences {
|
||||
|
||||
private fun encryptedPreferences(npub: String? = null): SharedPreferences {
|
||||
return if (BuildConfig.DEBUG && DEBUG_PLAINTEXT_PREFERENCES) {
|
||||
val preferenceFile = if (npub == null) "testing_only" else "testing_only_$npub"
|
||||
val preferenceFile = if (npub == null) "debug_prefs" else "debug_prefs_$npub"
|
||||
Amethyst.instance.getSharedPreferences(preferenceFile, Context.MODE_PRIVATE)
|
||||
} else {
|
||||
return EncryptedStorage.preferences(npub)
|
||||
@ -103,9 +119,13 @@ object LocalPreferences {
|
||||
/**
|
||||
* Clears the preferences for a given npub, deletes the preferences xml file,
|
||||
* and switches the user to the first account in the list if it exists
|
||||
*
|
||||
* We need to use `commit()` to write changes to disk and release the file
|
||||
* lock so that it can be deleted. If we use `apply()` there is a race
|
||||
* condition and the file will probably not be deleted
|
||||
*/
|
||||
@SuppressLint("ApplySharedPref")
|
||||
fun clearEncryptedStorage(npub: String) {
|
||||
fun updatePrefsForLogout(npub: String) {
|
||||
val userPrefs = encryptedPreferences(npub)
|
||||
userPrefs.edit().clear().commit()
|
||||
removeAccount(npub)
|
||||
@ -119,7 +139,12 @@ object LocalPreferences {
|
||||
}
|
||||
}
|
||||
|
||||
fun findAllLocalAccounts(): List<AccountInfo> {
|
||||
fun updatePrefsForLogin(account: Account) {
|
||||
setCurrentAccount(account)
|
||||
saveToEncryptedStorage(account)
|
||||
}
|
||||
|
||||
fun allSavedAccounts(): List<AccountInfo> {
|
||||
return savedAccounts.map { npub ->
|
||||
val prefs = encryptedPreferences(npub)
|
||||
|
||||
@ -132,12 +157,6 @@ object LocalPreferences {
|
||||
}
|
||||
}
|
||||
|
||||
fun setCurrentAccount(account: Account) {
|
||||
val npub = account.userProfile().pubkeyNpub()
|
||||
currentAccount = npub
|
||||
addAccount(npub)
|
||||
}
|
||||
|
||||
fun saveToEncryptedStorage(account: Account) {
|
||||
val prefs = encryptedPreferences(account.userProfile().pubkeyNpub())
|
||||
prefs.edit().apply {
|
||||
@ -157,11 +176,6 @@ object LocalPreferences {
|
||||
}.apply()
|
||||
}
|
||||
|
||||
fun login(account: Account) {
|
||||
setCurrentAccount(account)
|
||||
saveToEncryptedStorage(account)
|
||||
}
|
||||
|
||||
fun loadFromEncryptedStorage(): Account? {
|
||||
encryptedPreferences(currentAccount).apply {
|
||||
val pubKey = getString(PrefKeys.NOSTR_PUBKEY, null) ?: return null
|
||||
@ -183,7 +197,8 @@ object LocalPreferences {
|
||||
|
||||
val latestContactList = try {
|
||||
getString(PrefKeys.LATEST_CONTACT_LIST, null)?.let {
|
||||
Event.gson.fromJson(it, Event::class.java).getRefinedEvent(true) as ContactListEvent
|
||||
Event.gson.fromJson(it, Event::class.java)
|
||||
.getRefinedEvent(true) as ContactListEvent
|
||||
}
|
||||
} catch (e: Throwable) {
|
||||
e.printStackTrace()
|
||||
@ -192,7 +207,10 @@ object LocalPreferences {
|
||||
|
||||
val languagePreferences = try {
|
||||
getString(PrefKeys.LANGUAGE_PREFS, null)?.let {
|
||||
gson.fromJson(it, object : TypeToken<Map<String, String>>() {}.type) as Map<String, String>
|
||||
gson.fromJson(
|
||||
it,
|
||||
object : TypeToken<Map<String, String>>() {}.type
|
||||
) as Map<String, String>
|
||||
} ?: mapOf()
|
||||
} catch (e: Throwable) {
|
||||
e.printStackTrace()
|
||||
@ -227,4 +245,45 @@ object LocalPreferences {
|
||||
return getLong(PrefKeys.LAST_READ(route), 0)
|
||||
}
|
||||
}
|
||||
|
||||
fun migrateSingleUserPrefs() {
|
||||
if (currentAccount != null) return
|
||||
|
||||
val pubkey = encryptedPreferences().getString(PrefKeys.NOSTR_PUBKEY, null) ?: return
|
||||
val npub = Hex.decode(pubkey).toNpub()
|
||||
|
||||
val stringPrefs = listOf(
|
||||
PrefKeys.NOSTR_PRIVKEY,
|
||||
PrefKeys.NOSTR_PUBKEY,
|
||||
PrefKeys.RELAYS,
|
||||
PrefKeys.LANGUAGE_PREFS,
|
||||
PrefKeys.TRANSLATE_TO,
|
||||
PrefKeys.ZAP_AMOUNTS,
|
||||
PrefKeys.LATEST_CONTACT_LIST
|
||||
)
|
||||
|
||||
val stringSetPrefs = listOf(
|
||||
PrefKeys.FOLLOWING_CHANNELS,
|
||||
PrefKeys.HIDDEN_USERS,
|
||||
PrefKeys.DONT_TRANSLATE_FROM
|
||||
)
|
||||
|
||||
encryptedPreferences().apply {
|
||||
val appPrefs = this
|
||||
encryptedPreferences(npub).edit().apply {
|
||||
val userPrefs = this
|
||||
|
||||
stringPrefs.forEach { userPrefs.putString(it, appPrefs.getString(it, null)) }
|
||||
stringSetPrefs.forEach { userPrefs.putStringSet(it, appPrefs.getStringSet(it, null)) }
|
||||
userPrefs.putBoolean(
|
||||
PrefKeys.HIDE_DELETE_REQUEST_INFO,
|
||||
appPrefs.getBoolean(PrefKeys.HIDE_DELETE_REQUEST_INFO, false)
|
||||
)
|
||||
}.apply()
|
||||
}
|
||||
|
||||
encryptedPreferences().edit().clear().apply()
|
||||
addAccount(npub)
|
||||
currentAccount = npub
|
||||
}
|
||||
}
|
||||
|
@ -14,6 +14,7 @@ import coil.ImageLoader
|
||||
import coil.decode.GifDecoder
|
||||
import coil.decode.ImageDecoderDecoder
|
||||
import coil.decode.SvgDecoder
|
||||
import com.vitorpamplona.amethyst.LocalPreferences
|
||||
import com.vitorpamplona.amethyst.ServiceManager
|
||||
import com.vitorpamplona.amethyst.service.nip19.Nip19
|
||||
import com.vitorpamplona.amethyst.service.relays.Client
|
||||
@ -48,6 +49,8 @@ class MainActivity : FragmentActivity() {
|
||||
.build()
|
||||
}
|
||||
|
||||
LocalPreferences.migrateSingleUserPrefs()
|
||||
|
||||
setContent {
|
||||
AmethystTheme {
|
||||
// A surface container using the 'background' color from the theme
|
||||
|
@ -55,7 +55,7 @@ fun AccountSwitchBottomSheet(
|
||||
accountStateViewModel: AccountStateViewModel
|
||||
) {
|
||||
val context = LocalContext.current
|
||||
val accounts = LocalPreferences.findAllLocalAccounts()
|
||||
val accounts = LocalPreferences.allSavedAccounts()
|
||||
|
||||
val accountState by accountViewModel.accountLiveData.observeAsState()
|
||||
val account = accountState?.account ?: return
|
||||
|
@ -51,18 +51,18 @@ class AccountStateViewModel() : ViewModel() {
|
||||
Account(Persona(Hex.decode(key)))
|
||||
}
|
||||
|
||||
LocalPreferences.login(account)
|
||||
LocalPreferences.updatePrefsForLogin(account)
|
||||
login(account)
|
||||
}
|
||||
|
||||
fun newKey() {
|
||||
val account = Account(Persona())
|
||||
LocalPreferences.login(account)
|
||||
LocalPreferences.updatePrefsForLogin(account)
|
||||
login(account)
|
||||
}
|
||||
|
||||
fun login(account: Account) {
|
||||
LocalPreferences.login(account)
|
||||
LocalPreferences.updatePrefsForLogin(account)
|
||||
|
||||
if (account.loggedIn.privKey != null) {
|
||||
_accountContent.update { AccountState.LoggedIn(account) }
|
||||
@ -105,7 +105,7 @@ class AccountStateViewModel() : ViewModel() {
|
||||
|
||||
_accountContent.update { AccountState.LoggedOff }
|
||||
|
||||
LocalPreferences.clearEncryptedStorage(npub)
|
||||
LocalPreferences.updatePrefsForLogout(npub)
|
||||
tryLoginExistingAccount()
|
||||
}
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user