From bb7a8965c1f8340e39643b271d3cd8c0d755169a Mon Sep 17 00:00:00 2001 From: Rahul Raveendran Date: Tue, 11 Jun 2024 20:17:29 +0530 Subject: [PATCH 1/5] Renamed encrypted preference file to have the blueshift package name --- .../main/java/com/blueshift/BlueshiftEncryptedPreferences.kt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/android-sdk/src/main/java/com/blueshift/BlueshiftEncryptedPreferences.kt b/android-sdk/src/main/java/com/blueshift/BlueshiftEncryptedPreferences.kt index a3992aea..9b34ee3d 100644 --- a/android-sdk/src/main/java/com/blueshift/BlueshiftEncryptedPreferences.kt +++ b/android-sdk/src/main/java/com/blueshift/BlueshiftEncryptedPreferences.kt @@ -6,7 +6,7 @@ import androidx.security.crypto.EncryptedSharedPreferences import androidx.security.crypto.MasterKeys object BlueshiftEncryptedPreferences { - private val PREF_NAME = "blueshift_sdk_preferences" + private const val PREF_NAME = "com.blueshift.encrypted.preferences" private lateinit var sharedPreferences: SharedPreferences From 82f9183ac81d6bf1111a503c2c30032956bb4db5 Mon Sep 17 00:00:00 2001 From: Rahul Raveendran Date: Tue, 11 Jun 2024 22:06:17 +0530 Subject: [PATCH 2/5] Removed the check for email address change to fire identify event --- .../com/blueshift/BlueShiftPreference.java | 32 ++++--------------- .../main/java/com/blueshift/Blueshift.java | 5 ++- .../java/com/blueshift/model/UserInfo.java | 8 +++++ .../request_queue/RequestDispatcher.java | 16 +--------- 4 files changed, 20 insertions(+), 41 deletions(-) diff --git a/android-sdk/src/main/java/com/blueshift/BlueShiftPreference.java b/android-sdk/src/main/java/com/blueshift/BlueShiftPreference.java index c75f76fe..004795fa 100644 --- a/android-sdk/src/main/java/com/blueshift/BlueShiftPreference.java +++ b/android-sdk/src/main/java/com/blueshift/BlueShiftPreference.java @@ -126,31 +126,6 @@ public static boolean didPushPermissionStatusChange(Context context) { return true; } - public static boolean isEmailAlreadyIdentified(Context context, String email) { - boolean result = false; - - if (context != null && !TextUtils.isEmpty(email)) { - SharedPreferences preferences = getEmailPreference(context); - if (preferences != null) { - result = preferences.getBoolean(email, false); - } - } - - return result; - } - - public static void markEmailAsIdentified(Context context, String email) { - if (context != null && !TextUtils.isEmpty(email)) { - SharedPreferences preferences = getEmailPreference(context); - if (preferences != null) { - preferences - .edit() - .putBoolean(email, true) - .apply(); - } - } - } - private static SharedPreferences getBlueshiftPreferences(Context context) { SharedPreferences preferences = null; @@ -161,6 +136,13 @@ private static SharedPreferences getBlueshiftPreferences(Context context) { return preferences; } + public static void removeCachedEmailAddress(Context context) { + SharedPreferences preferences = getEmailPreference(context); + if (preferences != null) { + preferences.edit().clear().apply(); + } + } + private static SharedPreferences getEmailPreference(Context context) { SharedPreferences preferences = null; diff --git a/android-sdk/src/main/java/com/blueshift/Blueshift.java b/android-sdk/src/main/java/com/blueshift/Blueshift.java index 15e1d86f..1e4e3519 100644 --- a/android-sdk/src/main/java/com/blueshift/Blueshift.java +++ b/android-sdk/src/main/java/com/blueshift/Blueshift.java @@ -354,7 +354,10 @@ public void getLiveContentByCustomerId(@NonNull String slot, HashMap Date: Wed, 12 Jun 2024 12:24:54 +0530 Subject: [PATCH 3/5] Fixed the confusion regarding naming --- .../java/com/blueshift/model/UserInfo.java | 44 +++++++++---------- 1 file changed, 22 insertions(+), 22 deletions(-) diff --git a/android-sdk/src/main/java/com/blueshift/model/UserInfo.java b/android-sdk/src/main/java/com/blueshift/model/UserInfo.java index 83b0e31c..1e4d585a 100644 --- a/android-sdk/src/main/java/com/blueshift/model/UserInfo.java +++ b/android-sdk/src/main/java/com/blueshift/model/UserInfo.java @@ -71,11 +71,11 @@ public static UserInfo getInstance(Context context) { } } - private static String getLegacyPreferenceFile(@NonNull Context context) { + private static String getSharedPreferencesFilename(@NonNull Context context) { return context.getPackageName() + "." + PREF_FILE; } - private static String getLegacyPreferenceKey(@NonNull Context context) { + private static String getSharedPreferencesKey(@NonNull Context context) { return context.getPackageName() + "." + PREF_KEY; } @@ -86,15 +86,15 @@ private static UserInfo load(@NonNull Context context) { } static UserInfo load(Context context, boolean encryptionEnabled) { - return encryptionEnabled ? loadEncrypted(context) : loadLegacy(context); + return encryptionEnabled ? loadFromEncryptedSharedPreferences(context) : loadFromSharedPreferences(context); } - private static UserInfo loadLegacy(@NonNull Context context) { + private static UserInfo loadFromSharedPreferences(@NonNull Context context) { UserInfo userInfo = null; - BlueshiftLogger.d(TAG, "Loading from legacy shared preference."); - SharedPreferences preferences = context.getSharedPreferences(getLegacyPreferenceFile(context), Context.MODE_PRIVATE); - String json = preferences.getString(getLegacyPreferenceKey(context), null); + BlueshiftLogger.d(TAG, "Loading from SharedPreferences."); + SharedPreferences preferences = context.getSharedPreferences(getSharedPreferencesFilename(context), Context.MODE_PRIVATE); + String json = preferences.getString(getSharedPreferencesKey(context), null); if (json != null) { try { userInfo = new Gson().fromJson(json, UserInfo.class); @@ -106,7 +106,7 @@ private static UserInfo loadLegacy(@NonNull Context context) { return userInfo; } - private static UserInfo loadEncrypted(@NonNull Context context) { + private static UserInfo loadFromEncryptedSharedPreferences(@NonNull Context context) { UserInfo userInfo = null; BlueshiftLogger.d(TAG, "Loading from encrypted preference."); @@ -114,19 +114,19 @@ private static UserInfo loadEncrypted(@NonNull Context context) { if (json == null) { // The new secure store doesn't have the user info. Let's check in the old preference // file and copy over the data if present. - SharedPreferences pref = context.getSharedPreferences(getLegacyPreferenceFile(context), Context.MODE_PRIVATE); - String legacyJson = pref.getString(getLegacyPreferenceKey(context), null); - if (legacyJson != null) { - BlueshiftLogger.d(TAG, "Found data inside the legacy preference. Copying it to the encrypted preference."); + SharedPreferences pref = context.getSharedPreferences(getSharedPreferencesFilename(context), Context.MODE_PRIVATE); + String spUserJson = pref.getString(getSharedPreferencesKey(context), null); + if (spUserJson != null) { + BlueshiftLogger.d(TAG, "Found user data inside the SharedPreferences. Copying it to the EncryptedSharedPreferences."); try { - userInfo = new Gson().fromJson(legacyJson, UserInfo.class); + userInfo = new Gson().fromJson(spUserJson, UserInfo.class); // Save it to secure store for loading next time. - userInfo.saveEncrypted(); + userInfo.saveToEncryptedSharedPreferences(); // Clear the old preference for privacy reasons. - BlueshiftLogger.d(TAG, "Clear the legacy preference."); + BlueshiftLogger.d(TAG, "Clear the SharedPreferences."); pref.edit().clear().apply(); // Remove cached email address information (If found) - BlueshiftLogger.d(TAG, "Clear the email preference."); + BlueshiftLogger.d(TAG, "Clear the email from SharedPreferences."); BlueShiftPreference.removeCachedEmailAddress(context); } catch (Exception e) { BlueshiftLogger.e(TAG, e); @@ -185,19 +185,19 @@ public void save(@NonNull Context context) { void save(Context context, boolean encryptionEnabled) { if (encryptionEnabled) { - saveEncrypted(); + saveToEncryptedSharedPreferences(); } else { - saveLegacy(context); + saveToSharedPreferences(context); } } - private void saveLegacy(Context context) { + private void saveToSharedPreferences(Context context) { String json = new Gson().toJson(this); - context.getSharedPreferences(getLegacyPreferenceFile(context), Context.MODE_PRIVATE) - .edit().putString(getLegacyPreferenceKey(context), json).apply(); + context.getSharedPreferences(getSharedPreferencesFilename(context), Context.MODE_PRIVATE) + .edit().putString(getSharedPreferencesKey(context), json).apply(); } - private void saveEncrypted() { + private void saveToEncryptedSharedPreferences() { String json = new Gson().toJson(this); BlueshiftEncryptedPreferences.INSTANCE.putString(PREF_KEY_ENCRYPTED, json); } From c14342377a409fc105a20dffec9d00f105e92b75 Mon Sep 17 00:00:00 2001 From: Rahul Raveendran Date: Wed, 12 Jun 2024 12:32:30 +0530 Subject: [PATCH 4/5] Fixed the confusion regarding naming of the flag --- android-sdk/src/main/java/com/blueshift/Blueshift.java | 2 +- .../main/java/com/blueshift/model/Configuration.java | 10 +++++----- .../src/main/java/com/blueshift/model/UserInfo.java | 4 ++-- 3 files changed, 8 insertions(+), 8 deletions(-) diff --git a/android-sdk/src/main/java/com/blueshift/Blueshift.java b/android-sdk/src/main/java/com/blueshift/Blueshift.java index 1e4e3519..8318de38 100644 --- a/android-sdk/src/main/java/com/blueshift/Blueshift.java +++ b/android-sdk/src/main/java/com/blueshift/Blueshift.java @@ -355,7 +355,7 @@ public void initialize(@NonNull Configuration configuration) { mConfiguration = configuration; // initialize the encrypted shared preferences if enabled. - if (configuration.shouldEncryptUserInfo()) { + if (configuration.shouldSaveUserInfoAsEncrypted()) { BlueshiftEncryptedPreferences.INSTANCE.init(mContext); } diff --git a/android-sdk/src/main/java/com/blueshift/model/Configuration.java b/android-sdk/src/main/java/com/blueshift/model/Configuration.java index fb44d716..bbf829d2 100644 --- a/android-sdk/src/main/java/com/blueshift/model/Configuration.java +++ b/android-sdk/src/main/java/com/blueshift/model/Configuration.java @@ -60,7 +60,7 @@ public class Configuration { // Defines is we should store user info in plain text or in encrypted form. // Default value is false to make it backward compatible. - private boolean shouldEncryptUserInfo = false; + private boolean saveUserInfoAsEncrypted = false; public Configuration() { // Setting default region to the US. @@ -98,12 +98,12 @@ public Configuration() { autoAppOpenInterval = 86400; } - public boolean shouldEncryptUserInfo() { - return shouldEncryptUserInfo; + public boolean shouldSaveUserInfoAsEncrypted() { + return saveUserInfoAsEncrypted; } - public void setShouldEncryptUserInfo(boolean shouldEncryptUserInfo) { - this.shouldEncryptUserInfo = shouldEncryptUserInfo; + public void setSaveUserInfoAsEncrypted(boolean saveUserInfoAsEncrypted) { + this.saveUserInfoAsEncrypted = saveUserInfoAsEncrypted; } public boolean isPushAppLinksEnabled() { diff --git a/android-sdk/src/main/java/com/blueshift/model/UserInfo.java b/android-sdk/src/main/java/com/blueshift/model/UserInfo.java index 1e4d585a..b588eb4a 100644 --- a/android-sdk/src/main/java/com/blueshift/model/UserInfo.java +++ b/android-sdk/src/main/java/com/blueshift/model/UserInfo.java @@ -81,7 +81,7 @@ private static String getSharedPreferencesKey(@NonNull Context context) { private static UserInfo load(@NonNull Context context) { Configuration configuration = BlueshiftUtils.getConfiguration(context); - boolean isEncryptionEnabled = configuration != null && configuration.shouldEncryptUserInfo(); + boolean isEncryptionEnabled = configuration != null && configuration.shouldSaveUserInfoAsEncrypted(); return load(context, isEncryptionEnabled); } @@ -179,7 +179,7 @@ public HashMap toHashMap() { public void save(@NonNull Context context) { Configuration configuration = BlueshiftUtils.getConfiguration(context); - boolean isEncryptionEnabled = configuration != null && configuration.shouldEncryptUserInfo(); + boolean isEncryptionEnabled = configuration != null && configuration.shouldSaveUserInfoAsEncrypted(); save(context, isEncryptionEnabled); } From 19b364215a8168eb6e394c8b4b222bbc0e5786f9 Mon Sep 17 00:00:00 2001 From: Rahul Raveendran Date: Wed, 12 Jun 2024 12:47:03 +0530 Subject: [PATCH 5/5] Fixed the tests wit additional test case and naming corrections --- .../java/com/blueshift/model/UserInfoTest.kt | 41 +++++++++++-------- 1 file changed, 25 insertions(+), 16 deletions(-) diff --git a/android-sdk/src/androidTest/java/com/blueshift/model/UserInfoTest.kt b/android-sdk/src/androidTest/java/com/blueshift/model/UserInfoTest.kt index 31be6d49..88321951 100644 --- a/android-sdk/src/androidTest/java/com/blueshift/model/UserInfoTest.kt +++ b/android-sdk/src/androidTest/java/com/blueshift/model/UserInfoTest.kt @@ -9,13 +9,13 @@ import org.junit.Test class UserInfoTest { private lateinit var context: Context - private lateinit var legacyPreference: SharedPreferences + private lateinit var sharedPreferences: SharedPreferences - private fun oldPreferenceFile(context: Context): String { + private fun sharedPreferencesFilename(context: Context): String { return context.packageName + ".user_info_file" } - private fun oldPreferenceKey(context: Context): String { + private fun sharedPreferencesKey(context: Context): String { return context.packageName + ".user_info_key" } @@ -24,10 +24,10 @@ class UserInfoTest { context = InstrumentationRegistry.getInstrumentation().targetContext // Reset old preferences - legacyPreference = context.getSharedPreferences( - oldPreferenceFile(context), Context.MODE_PRIVATE + sharedPreferences = context.getSharedPreferences( + sharedPreferencesFilename(context), Context.MODE_PRIVATE ) - legacyPreference.edit().remove(oldPreferenceKey(context)).commit() + sharedPreferences.edit().remove(sharedPreferencesKey(context)).commit() // Reset new preferences BlueshiftEncryptedPreferences.init(context) @@ -44,18 +44,27 @@ class UserInfoTest { @Test fun load_updatedFromOldSDK_returnSameUserInfoObject() { + val emailPreferencesKey = "john.doe@examplepetstore.com" + val emailPreferencesFileName = "${context.packageName}.BsftEmailPrefFile" + val emailPreferences = context.getSharedPreferences(emailPreferencesFileName, Context.MODE_PRIVATE) + emailPreferences.edit().putBoolean(emailPreferencesKey, true).apply() + // Mock the presence of a user object in the old preference. - legacyPreference.edit().putString(oldPreferenceKey(context), USER_JSON).apply() + sharedPreferences.edit().putString(sharedPreferencesKey(context), USER_JSON).apply() // When encryption is not enabled, the user info class should provide the same value // for its members as we saved in the old preference. - val userinfo = UserInfo.load(context, false) - assert(userinfo.name == JOHN) + val name = UserInfo.load(context, false).name + assert(name == JOHN) - // When encryption is not enabled, the user info class should provide the same value + // When encryption is enabled, the user info class should provide the same value // for its members as we saved in the old preference. - val userinfo2 = UserInfo.load(context, true) - assert(userinfo2.name == JOHN) + val encryptedName = UserInfo.load(context, true).name + assert(encryptedName == JOHN) + + // When encryption is enabled, the data stored in email preferences (if any) should be deleted. + val status = emailPreferences.getBoolean(emailPreferencesKey, false) + assert(!status) // Kill the existing instance for the next test. UserInfo.killInstance() @@ -64,7 +73,7 @@ class UserInfoTest { @Test fun load_updatedFromOldSDK_copiesTheContentOfOldPrefToNewPref() { // Mock the presence of a user object in the old preference. - legacyPreference.edit().putString(oldPreferenceKey(context), USER_JSON).apply() + sharedPreferences.edit().putString(sharedPreferencesKey(context), USER_JSON).apply() // case1 : When encryption is not enabled. val userInfo = UserInfo.load(context, false) @@ -82,7 +91,7 @@ class UserInfoTest { @Test fun load_updatedFromOldSDK_deletesTheDataInOldPreference() { // Mock the presence of a user object in the old preference. - legacyPreference.edit().putString(oldPreferenceKey(context), USER_JSON).apply() + sharedPreferences.edit().putString(sharedPreferencesKey(context), USER_JSON).apply() // case1 : When encryption is not enabled. val userInfo = UserInfo.load(context, false) @@ -91,8 +100,8 @@ class UserInfoTest { // case2 : When encryption is enabled. UserInfo.load(context, true) // Make sure the value stored in the old preferences is removed after copying it to the new preferences. - val legacyJson = legacyPreference.getString(oldPreferenceKey(context), null) - assert(legacyJson == null) + val spUserJson = sharedPreferences.getString(sharedPreferencesKey(context), null) + assert(spUserJson == null) // Kill the existing instance for the next test. UserInfo.killInstance()