Loading cardinal-android/app/src/main/java/earth/maps/cardinal/data/AppPreferences.kt +13 −5 Original line number Diff line number Diff line Loading @@ -378,8 +378,10 @@ class AppPreferences internal constructor( fun saveMurenaAccount(name: String?, type: String?) { if (name.isNullOrBlank() || type.isNullOrBlank()) { murenaAccountLinkageStore.saveAccountName(null) murenaAccountLinkageStore.saveAccountType(null) } else { murenaAccountLinkageStore.saveAccountName(name) murenaAccountLinkageStore.saveAccountType(type) } prefs.edit { Loading @@ -400,16 +402,22 @@ class AppPreferences internal constructor( ?: return null murenaAccountLinkageStore.saveAccountName(legacyAccountName) val legacyType = prefs.getString(KEY_MURENA_ACCOUNT_TYPE, null) ?.takeIf { it.isNotBlank() } if (legacyType != null) { murenaAccountLinkageStore.saveAccountType(legacyType) } clearLegacyMurenaAccount() return legacyAccountName } fun loadMurenaAccountType(): String? { return if (loadMurenaAccountName().isNullOrBlank()) { null } else { MURENA_WORKSPACE_ACCOUNT_TYPE } if (loadMurenaAccountName().isNullOrBlank()) return null val persistedType = murenaAccountLinkageStore.loadAccountType() if (!persistedType.isNullOrBlank()) return persistedType return MURENA_WORKSPACE_ACCOUNT_TYPE } private fun clearLegacyMurenaAccount() { Loading cardinal-android/app/src/main/java/earth/maps/cardinal/data/MurenaAccountLinkageStore.kt +29 −0 Original line number Diff line number Diff line Loading @@ -34,6 +34,8 @@ import javax.crypto.spec.GCMParameterSpec internal interface MurenaAccountLinkageStore { fun saveAccountName(accountName: String?) fun loadAccountName(): String? fun saveAccountType(accountType: String?) fun loadAccountType(): String? } internal class KeystoreMurenaAccountLinkageStore(context: Context) : MurenaAccountLinkageStore { Loading Loading @@ -66,6 +68,32 @@ internal class KeystoreMurenaAccountLinkageStore(context: Context) : MurenaAccou }.getOrNull() } override fun saveAccountType(accountType: String?) { if (accountType.isNullOrBlank()) { prefs.edit { remove(KEY_ACCOUNT_TYPE) } return } runCatching { encrypt(accountType) }.onSuccess { encryptedAccountType -> prefs.edit { putString(KEY_ACCOUNT_TYPE, encryptedAccountType) } }.onFailure { exception -> Log.e(TAG, "Unable to persist encrypted Murena account type", exception) prefs.edit { remove(KEY_ACCOUNT_TYPE) } } } override fun loadAccountType(): String? { val encryptedAccountType = prefs.getString(KEY_ACCOUNT_TYPE, null) ?: return null return runCatching { decrypt(encryptedAccountType).takeIf { it.isNotBlank() } }.onFailure { exception -> Log.w(TAG, "Unable to read encrypted Murena account type", exception) prefs.edit { remove(KEY_ACCOUNT_TYPE) } }.getOrNull() } private fun encrypt(value: String): String { val cipher = Cipher.getInstance(TRANSFORMATION) cipher.init(Cipher.ENCRYPT_MODE, getOrCreateSecretKey()) Loading Loading @@ -129,6 +157,7 @@ internal class KeystoreMurenaAccountLinkageStore(context: Context) : MurenaAccou private const val TAG = "MurenaAccountLinkage" private const val PREFS_NAME = "murena_account_linkage" private const val KEY_ACCOUNT_NAME = "account_name" private const val KEY_ACCOUNT_TYPE = "account_type" private const val KEY_ALIAS = "earth.maps.cardinal.murena_account_linkage" private const val ANDROID_KEYSTORE = "AndroidKeyStore" private const val TRANSFORMATION = "AES/GCM/NoPadding" Loading Loading
cardinal-android/app/src/main/java/earth/maps/cardinal/data/AppPreferences.kt +13 −5 Original line number Diff line number Diff line Loading @@ -378,8 +378,10 @@ class AppPreferences internal constructor( fun saveMurenaAccount(name: String?, type: String?) { if (name.isNullOrBlank() || type.isNullOrBlank()) { murenaAccountLinkageStore.saveAccountName(null) murenaAccountLinkageStore.saveAccountType(null) } else { murenaAccountLinkageStore.saveAccountName(name) murenaAccountLinkageStore.saveAccountType(type) } prefs.edit { Loading @@ -400,16 +402,22 @@ class AppPreferences internal constructor( ?: return null murenaAccountLinkageStore.saveAccountName(legacyAccountName) val legacyType = prefs.getString(KEY_MURENA_ACCOUNT_TYPE, null) ?.takeIf { it.isNotBlank() } if (legacyType != null) { murenaAccountLinkageStore.saveAccountType(legacyType) } clearLegacyMurenaAccount() return legacyAccountName } fun loadMurenaAccountType(): String? { return if (loadMurenaAccountName().isNullOrBlank()) { null } else { MURENA_WORKSPACE_ACCOUNT_TYPE } if (loadMurenaAccountName().isNullOrBlank()) return null val persistedType = murenaAccountLinkageStore.loadAccountType() if (!persistedType.isNullOrBlank()) return persistedType return MURENA_WORKSPACE_ACCOUNT_TYPE } private fun clearLegacyMurenaAccount() { Loading
cardinal-android/app/src/main/java/earth/maps/cardinal/data/MurenaAccountLinkageStore.kt +29 −0 Original line number Diff line number Diff line Loading @@ -34,6 +34,8 @@ import javax.crypto.spec.GCMParameterSpec internal interface MurenaAccountLinkageStore { fun saveAccountName(accountName: String?) fun loadAccountName(): String? fun saveAccountType(accountType: String?) fun loadAccountType(): String? } internal class KeystoreMurenaAccountLinkageStore(context: Context) : MurenaAccountLinkageStore { Loading Loading @@ -66,6 +68,32 @@ internal class KeystoreMurenaAccountLinkageStore(context: Context) : MurenaAccou }.getOrNull() } override fun saveAccountType(accountType: String?) { if (accountType.isNullOrBlank()) { prefs.edit { remove(KEY_ACCOUNT_TYPE) } return } runCatching { encrypt(accountType) }.onSuccess { encryptedAccountType -> prefs.edit { putString(KEY_ACCOUNT_TYPE, encryptedAccountType) } }.onFailure { exception -> Log.e(TAG, "Unable to persist encrypted Murena account type", exception) prefs.edit { remove(KEY_ACCOUNT_TYPE) } } } override fun loadAccountType(): String? { val encryptedAccountType = prefs.getString(KEY_ACCOUNT_TYPE, null) ?: return null return runCatching { decrypt(encryptedAccountType).takeIf { it.isNotBlank() } }.onFailure { exception -> Log.w(TAG, "Unable to read encrypted Murena account type", exception) prefs.edit { remove(KEY_ACCOUNT_TYPE) } }.getOrNull() } private fun encrypt(value: String): String { val cipher = Cipher.getInstance(TRANSFORMATION) cipher.init(Cipher.ENCRYPT_MODE, getOrCreateSecretKey()) Loading Loading @@ -129,6 +157,7 @@ internal class KeystoreMurenaAccountLinkageStore(context: Context) : MurenaAccou private const val TAG = "MurenaAccountLinkage" private const val PREFS_NAME = "murena_account_linkage" private const val KEY_ACCOUNT_NAME = "account_name" private const val KEY_ACCOUNT_TYPE = "account_type" private const val KEY_ALIAS = "earth.maps.cardinal.murena_account_linkage" private const val ANDROID_KEYSTORE = "AndroidKeyStore" private const val TRANSFORMATION = "AES/GCM/NoPadding" Loading