diff --git a/buildSrc/src/main/kotlin/io.customer/android/Dependencies.kt b/buildSrc/src/main/kotlin/io.customer/android/Dependencies.kt index 44d58abea..0c71b12c1 100644 --- a/buildSrc/src/main/kotlin/io.customer/android/Dependencies.kt +++ b/buildSrc/src/main/kotlin/io.customer/android/Dependencies.kt @@ -3,6 +3,8 @@ package io.customer.android object Dependencies { const val androidGradlePlugin = "com.android.tools.build:gradle:${Versions.ANDROID_GRADLE_PLUGIN}" + const val androidxSecurityCrypto = + "androidx.security:security-crypto:${Versions.ANDROIDX_SECURITY_CRYPTO}" const val androidxTestJunit = "androidx.test.ext:junit:${Versions.ANDROIDX_TEST_JUNIT}" const val androidxTestRunner = "androidx.test:runner:${Versions.ANDROIDX_TEST_RUNNER}" const val androidxTestRules = "androidx.test:rules:${Versions.ANDROIDX_TEST_RULES}" diff --git a/buildSrc/src/main/kotlin/io.customer/android/Versions.kt b/buildSrc/src/main/kotlin/io.customer/android/Versions.kt index 26cad265f..d4ff357a7 100644 --- a/buildSrc/src/main/kotlin/io.customer/android/Versions.kt +++ b/buildSrc/src/main/kotlin/io.customer/android/Versions.kt @@ -2,6 +2,9 @@ package io.customer.android object Versions { internal const val ANDROID_GRADLE_PLUGIN = "7.2.0" + + // Using alpha version as current stable version (1.0.0) has minSdkVersion 23 + internal const val ANDROIDX_SECURITY_CRYPTO = "1.1.0-alpha06" internal const val ANDROIDX_TEST_JUNIT = "1.1.4" internal const val ANDROIDX_TEST_RUNNER = "1.4.0" internal const val ANDROIDX_TEST_RULES = "1.4.0" diff --git a/messagingpush/src/main/AndroidManifest.xml b/messagingpush/src/main/AndroidManifest.xml index 2f4af990f..e3132f963 100644 --- a/messagingpush/src/main/AndroidManifest.xml +++ b/messagingpush/src/main/AndroidManifest.xml @@ -5,7 +5,7 @@ - + diff --git a/messagingpush/src/main/res/xml/backup_rules.xml b/messagingpush/src/main/res/xml/backup_rules.xml new file mode 100644 index 000000000..3a1c4ebcf --- /dev/null +++ b/messagingpush/src/main/res/xml/backup_rules.xml @@ -0,0 +1,8 @@ + + + + + diff --git a/sdk/build.gradle b/sdk/build.gradle index f7c7fde78..22668c82f 100644 --- a/sdk/build.gradle +++ b/sdk/build.gradle @@ -57,6 +57,7 @@ dependencies { implementation Dependencies.coroutinesCore implementation Dependencies.coroutinesAndroid + implementation Dependencies.androidxSecurityCrypto implementation Dependencies.retrofit implementation Dependencies.moshi implementation Dependencies.retrofitMoshiConverter diff --git a/sdk/src/main/java/io/customer/sdk/repository/preference/BasePreferenceRepository.kt b/sdk/src/main/java/io/customer/sdk/repository/preference/BasePreferenceRepository.kt index 514e37108..6961342b1 100644 --- a/sdk/src/main/java/io/customer/sdk/repository/preference/BasePreferenceRepository.kt +++ b/sdk/src/main/java/io/customer/sdk/repository/preference/BasePreferenceRepository.kt @@ -10,11 +10,8 @@ internal abstract class BasePreferenceRepository(val context: Context) { abstract val prefsName: String - internal val prefs: SharedPreferences - get() = context.applicationContext.getSharedPreferences( - prefsName, - Context.MODE_PRIVATE - ) + // Making this abstract so base class has option to use encrypted shared prefs + internal abstract val prefs: SharedPreferences // this would clear the prefs asynchronously open fun clearAll() { diff --git a/sdk/src/main/java/io/customer/sdk/repository/preference/SharedPreferenceRepository.kt b/sdk/src/main/java/io/customer/sdk/repository/preference/SharedPreferenceRepository.kt index 9defef649..31ddc4a12 100644 --- a/sdk/src/main/java/io/customer/sdk/repository/preference/SharedPreferenceRepository.kt +++ b/sdk/src/main/java/io/customer/sdk/repository/preference/SharedPreferenceRepository.kt @@ -1,6 +1,9 @@ package io.customer.sdk.repository.preference import android.content.Context +import android.content.SharedPreferences +import androidx.security.crypto.EncryptedSharedPreferences +import androidx.security.crypto.MasterKey import io.customer.sdk.Version import io.customer.sdk.data.model.Region import io.customer.sdk.data.store.Client @@ -16,8 +19,29 @@ internal interface SharedPreferenceRepository { internal class SharedPreferenceRepositoryImp(context: Context) : SharedPreferenceRepository, BasePreferenceRepository(context) { + // The file name used for storing shared preferences. + // This preference file should not be included in Auto Backup. + // Upon restoration, the encryption key originally used may no longer be present. + // To prevent this, ensure the file name matches the one excluded in backup_rules.xml. + // Read more: https://developer.android.com/reference/androidx/security/crypto/EncryptedSharedPreferences override val prefsName: String by lazy { - "io.customer.sdk.${context.packageName}.PREFERENCE_FILE_KEY" + "io.customer.sdk.EncryptedConfigCache" + } + + override val prefs: SharedPreferences + + init { + val masterKey = MasterKey.Builder(context) + .setKeyScheme(MasterKey.KeyScheme.AES256_GCM) + .build() + + prefs = EncryptedSharedPreferences.create( + context, + prefsName, + masterKey, + EncryptedSharedPreferences.PrefKeyEncryptionScheme.AES256_SIV, + EncryptedSharedPreferences.PrefValueEncryptionScheme.AES256_GCM + ) } override fun saveSettings( diff --git a/sdk/src/main/java/io/customer/sdk/repository/preference/SitePreferenceRepository.kt b/sdk/src/main/java/io/customer/sdk/repository/preference/SitePreferenceRepository.kt index 92f30c7a6..123d5fc0b 100644 --- a/sdk/src/main/java/io/customer/sdk/repository/preference/SitePreferenceRepository.kt +++ b/sdk/src/main/java/io/customer/sdk/repository/preference/SitePreferenceRepository.kt @@ -1,6 +1,7 @@ package io.customer.sdk.repository.preference import android.content.Context +import android.content.SharedPreferences import io.customer.sdk.CustomerIOConfig import io.customer.sdk.extensions.getDate import io.customer.sdk.extensions.putDate @@ -28,6 +29,12 @@ internal class SitePreferenceRepositoryImpl( "io.customer.sdk.${context.packageName}.${config.siteId}" } + override val prefs: SharedPreferences + get() = context.applicationContext.getSharedPreferences( + prefsName, + Context.MODE_PRIVATE + ) + companion object { private const val KEY_IDENTIFIER = "identifier" private const val KEY_DEVICE_TOKEN = "device_token"