Skip to content

Instantly share code, notes, and snippets.

@FrancescoJo
Last active March 17, 2022 05:32
Show Gist options
  • Save FrancescoJo/8753a63e1c6888c5d07ceb552c98104c to your computer and use it in GitHub Desktop.
Save FrancescoJo/8753a63e1c6888c5d07ceb552c98104c to your computer and use it in GitHub Desktop.
A SharedPreferences wrapper implementation with encryption/decryption, using CipherHelper implementation.
import android.content.SharedPreferences
/**
* A [android.content.SharedPreferences] wrapper that helps easy reading/writing values.
*
* @author Francesco Jo([email protected])
* @since 22 - Mar - 2018
*/
class SecureSharedPreferences(private val sharedPref: SharedPreferences) {
fun contains(key: String) = sharedPref.contains(key)
fun get(key: String, defaultValue: Boolean): Boolean = getInternal(key, defaultValue)
fun get(key: String, defaultValue: Int): Int = getInternal(key, defaultValue)
fun get(key: String, defaultValue: Long): Long = getInternal(key, defaultValue)
fun get(key: String, defaultValue: String): String = getInternal(key, defaultValue)
/**
* Client codes must handle ClassCastException by their own at the call site if happens.
*/
private fun <T : Any> getInternal(key: String, defaultValue: T): T {
val str = sharedPref.getString(key, "")
if (str.isNullOrEmpty()) {
return defaultValue
}
val value = AndroidCipherHelper.decrypt(str)
@Suppress("PlatformExtensionReceiverOfInline", "UNCHECKED_CAST", "IMPLICIT_CAST_TO_ANY")
return when(defaultValue) {
is Boolean -> value.toBoolean()
is Int -> value.toInt()
is Long -> value.toLong()
is String -> value
else -> throw IllegalArgumentException("defaultValue only could be one of these types: Boolean, Int, Long, String")
} as T
}
fun put(key: String, value: Boolean) = putInternal(key, value)
fun put(key: String, value: Int) = putInternal(key, value)
fun put(key: String, value: Long) = putInternal(key, value)
/**
* Due to the encryption layer limitations, input value must be shorter than [CipherHelper.KEY_LENGTH_BIT] bytes.
*/
fun put(key: String, value: String) = putInternal(key, value)
private fun putInternal(key: String, value: Any?) {
try {
sharedPref.edit().run({
if (value == null) {
remove(key)
} else {
putString(key, AndroidCipherHelper.encrypt(value.toString()))
}
apply()
})
} catch (e: Throwable) {
e.printStackTrace()
}
}
companion object {
fun wrap(sharedPref: SharedPreferences) = SecureSharedPreferences(sharedPref)
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment