security: encrypt credentials, caches, and harden lock screen
Auto Tag on Version Change / check-version (push) Successful in 6s
Auto Tag on Version Change / check-version (push) Successful in 6s
This commit is contained in:
@@ -32,7 +32,7 @@ object AccountCache {
|
||||
})
|
||||
}
|
||||
context.getSharedPreferences(PREFS, Context.MODE_PRIVATE)
|
||||
.edit().putString(KEY_MIB, arr.toString()).apply()
|
||||
.edit().putString(KEY_MIB, CacheEncryption.encrypt(arr.toString())).apply()
|
||||
}
|
||||
|
||||
fun saveBml(context: Context, accounts: List<MibAccount>) {
|
||||
@@ -55,13 +55,14 @@ object AccountCache {
|
||||
})
|
||||
}
|
||||
context.getSharedPreferences(PREFS, Context.MODE_PRIVATE)
|
||||
.edit().putString(KEY_BML, arr.toString()).apply()
|
||||
.edit().putString(KEY_BML, CacheEncryption.encrypt(arr.toString())).apply()
|
||||
}
|
||||
|
||||
fun loadBml(context: Context): List<MibAccount> {
|
||||
val json = context.getSharedPreferences(PREFS, Context.MODE_PRIVATE)
|
||||
val raw = context.getSharedPreferences(PREFS, Context.MODE_PRIVATE)
|
||||
.getString(KEY_BML, null) ?: return emptyList()
|
||||
return try {
|
||||
val json = CacheEncryption.decrypt(raw)
|
||||
val arr = JSONArray(json)
|
||||
(0 until arr.length()).map { i ->
|
||||
val o = arr.getJSONObject(i)
|
||||
@@ -90,9 +91,10 @@ object AccountCache {
|
||||
}
|
||||
|
||||
fun load(context: Context): List<MibAccount> {
|
||||
val json = context.getSharedPreferences(PREFS, Context.MODE_PRIVATE)
|
||||
val raw = context.getSharedPreferences(PREFS, Context.MODE_PRIVATE)
|
||||
.getString(KEY_MIB, null) ?: return emptyList()
|
||||
return try {
|
||||
val json = CacheEncryption.decrypt(raw)
|
||||
val arr = JSONArray(json)
|
||||
(0 until arr.length()).map { i ->
|
||||
val o = arr.getJSONObject(i)
|
||||
|
||||
@@ -0,0 +1,55 @@
|
||||
package sh.sar.basedbank.util
|
||||
|
||||
import android.security.keystore.KeyGenParameterSpec
|
||||
import android.security.keystore.KeyProperties
|
||||
import android.util.Base64
|
||||
import java.security.KeyStore
|
||||
import javax.crypto.Cipher
|
||||
import javax.crypto.KeyGenerator
|
||||
import javax.crypto.SecretKey
|
||||
import javax.crypto.spec.GCMParameterSpec
|
||||
|
||||
/**
|
||||
* Shared AES-256/GCM encryption for cache SharedPreferences and files.
|
||||
* Uses the same AndroidKeyStore key as CredentialStore so no extra key material is created.
|
||||
*/
|
||||
internal object CacheEncryption {
|
||||
|
||||
private const val KEY_ALIAS = "basedbank_credential_key"
|
||||
private const val TRANSFORMATION = "AES/GCM/NoPadding"
|
||||
|
||||
fun encrypt(plaintext: String): String {
|
||||
val cipher = Cipher.getInstance(TRANSFORMATION)
|
||||
cipher.init(Cipher.ENCRYPT_MODE, getOrCreateKey())
|
||||
val iv = cipher.iv
|
||||
val ct = cipher.doFinal(plaintext.toByteArray(Charsets.UTF_8))
|
||||
return Base64.encodeToString(iv, Base64.NO_WRAP) + ":" + Base64.encodeToString(ct, Base64.NO_WRAP)
|
||||
}
|
||||
|
||||
fun decrypt(encoded: String): String {
|
||||
val colon = encoded.indexOf(':')
|
||||
val iv = Base64.decode(encoded.substring(0, colon), Base64.NO_WRAP)
|
||||
val ct = Base64.decode(encoded.substring(colon + 1), Base64.NO_WRAP)
|
||||
val cipher = Cipher.getInstance(TRANSFORMATION)
|
||||
cipher.init(Cipher.DECRYPT_MODE, getOrCreateKey(), GCMParameterSpec(128, iv))
|
||||
return String(cipher.doFinal(ct), Charsets.UTF_8)
|
||||
}
|
||||
|
||||
private fun getOrCreateKey(): SecretKey {
|
||||
val ks = KeyStore.getInstance("AndroidKeyStore").also { it.load(null) }
|
||||
ks.getKey(KEY_ALIAS, null)?.let { return it as SecretKey }
|
||||
|
||||
val spec = KeyGenParameterSpec.Builder(
|
||||
KEY_ALIAS,
|
||||
KeyProperties.PURPOSE_ENCRYPT or KeyProperties.PURPOSE_DECRYPT
|
||||
)
|
||||
.setBlockModes(KeyProperties.BLOCK_MODE_GCM)
|
||||
.setEncryptionPaddings(KeyProperties.ENCRYPTION_PADDING_NONE)
|
||||
.setKeySize(256)
|
||||
.build()
|
||||
|
||||
return KeyGenerator.getInstance(KeyProperties.KEY_ALGORITHM_AES, "AndroidKeyStore")
|
||||
.also { it.init(spec) }
|
||||
.generateKey()
|
||||
}
|
||||
}
|
||||
@@ -37,7 +37,7 @@ object ContactsCache {
|
||||
put("profileId", c.profileId)
|
||||
})
|
||||
}
|
||||
prefs.putString(KEY_CONTACTS, contactsArr.toString())
|
||||
prefs.putString(KEY_CONTACTS, CacheEncryption.encrypt(contactsArr.toString()))
|
||||
|
||||
val catArr = JSONArray()
|
||||
for (cat in categories) {
|
||||
@@ -47,7 +47,7 @@ object ContactsCache {
|
||||
put("numBenef", cat.numBenef)
|
||||
})
|
||||
}
|
||||
prefs.putString(KEY_CATEGORIES, catArr.toString())
|
||||
prefs.putString(KEY_CATEGORIES, CacheEncryption.encrypt(catArr.toString()))
|
||||
prefs.apply()
|
||||
}
|
||||
|
||||
@@ -56,9 +56,10 @@ object ContactsCache {
|
||||
}
|
||||
|
||||
fun loadContacts(context: Context): List<MibBeneficiary> {
|
||||
val json = context.getSharedPreferences(PREFS, Context.MODE_PRIVATE)
|
||||
val raw = context.getSharedPreferences(PREFS, Context.MODE_PRIVATE)
|
||||
.getString(KEY_CONTACTS, null) ?: return emptyList()
|
||||
return try {
|
||||
val json = CacheEncryption.decrypt(raw)
|
||||
val arr = JSONArray(json)
|
||||
(0 until arr.length()).map { i ->
|
||||
val o = arr.getJSONObject(i)
|
||||
@@ -101,13 +102,14 @@ object ContactsCache {
|
||||
})
|
||||
}
|
||||
context.getSharedPreferences(PREFS, Context.MODE_PRIVATE)
|
||||
.edit().putString("bml_contacts", arr.toString()).apply()
|
||||
.edit().putString("bml_contacts", CacheEncryption.encrypt(arr.toString())).apply()
|
||||
}
|
||||
|
||||
fun loadBml(context: Context): List<MibBeneficiary> {
|
||||
val json = context.getSharedPreferences(PREFS, Context.MODE_PRIVATE)
|
||||
val raw = context.getSharedPreferences(PREFS, Context.MODE_PRIVATE)
|
||||
.getString("bml_contacts", null) ?: return emptyList()
|
||||
return try {
|
||||
val json = CacheEncryption.decrypt(raw)
|
||||
val arr = JSONArray(json)
|
||||
(0 until arr.length()).map { i ->
|
||||
val o = arr.getJSONObject(i)
|
||||
@@ -130,9 +132,10 @@ object ContactsCache {
|
||||
}
|
||||
|
||||
fun loadCategories(context: Context): List<MibBeneficiaryCategory> {
|
||||
val json = context.getSharedPreferences(PREFS, Context.MODE_PRIVATE)
|
||||
val raw = context.getSharedPreferences(PREFS, Context.MODE_PRIVATE)
|
||||
.getString(KEY_CATEGORIES, null) ?: return emptyList()
|
||||
return try {
|
||||
val json = CacheEncryption.decrypt(raw)
|
||||
val arr = JSONArray(json)
|
||||
(0 until arr.length()).map { i ->
|
||||
val o = arr.getJSONObject(i)
|
||||
|
||||
@@ -4,6 +4,7 @@ import android.content.Context
|
||||
import android.security.keystore.KeyGenParameterSpec
|
||||
import android.security.keystore.KeyProperties
|
||||
import android.util.Base64
|
||||
import org.json.JSONObject
|
||||
import java.security.KeyStore
|
||||
import javax.crypto.Cipher
|
||||
import javax.crypto.KeyGenerator
|
||||
@@ -19,6 +20,8 @@ class CredentialStore(context: Context) {
|
||||
data class MibCredentials(val username: String, val passwordHash: String, val otpSeed: String)
|
||||
data class BmlCredentials(val username: String, val password: String, val otpSeed: String)
|
||||
|
||||
// ── MIB login credentials ─────────────────────────────────────────────────
|
||||
|
||||
fun hasMibCredentials(): Boolean = prefs.contains("mib_enc_username")
|
||||
fun hasBmlCredentials(): Boolean = prefs.contains("bml_enc_username")
|
||||
|
||||
@@ -42,9 +45,7 @@ class CredentialStore(context: Context) {
|
||||
decrypt(encHash, key),
|
||||
decrypt(encSeed, key)
|
||||
)
|
||||
} catch (e: Exception) {
|
||||
null
|
||||
}
|
||||
} catch (_: Exception) { null }
|
||||
}
|
||||
|
||||
fun clearMibCredentials() {
|
||||
@@ -52,9 +53,44 @@ class CredentialStore(context: Context) {
|
||||
.remove("mib_enc_username")
|
||||
.remove("mib_enc_password_hash")
|
||||
.remove("mib_enc_otp_seed")
|
||||
.remove("mib_enc_key1")
|
||||
.remove("mib_enc_key2")
|
||||
.remove("mib_enc_app_id")
|
||||
.apply()
|
||||
}
|
||||
|
||||
// ── MIB session keys (key1/key2) and app ID ───────────────────────────────
|
||||
|
||||
fun saveMibKeys(key1: String, key2: String) {
|
||||
val key = getOrCreateKey()
|
||||
prefs.edit()
|
||||
.putString("mib_enc_key1", encrypt(key1, key))
|
||||
.putString("mib_enc_key2", encrypt(key2, key))
|
||||
.apply()
|
||||
}
|
||||
|
||||
fun loadMibKeys(): Pair<String, String>? {
|
||||
val key = getOrCreateKey()
|
||||
val encKey1 = prefs.getString("mib_enc_key1", null) ?: return null
|
||||
val encKey2 = prefs.getString("mib_enc_key2", null) ?: return null
|
||||
return try {
|
||||
Pair(decrypt(encKey1, key), decrypt(encKey2, key))
|
||||
} catch (_: Exception) { null }
|
||||
}
|
||||
|
||||
fun saveMibAppId(id: String) {
|
||||
val key = getOrCreateKey()
|
||||
prefs.edit().putString("mib_enc_app_id", encrypt(id, key)).apply()
|
||||
}
|
||||
|
||||
fun loadMibAppId(): String? {
|
||||
val key = getOrCreateKey()
|
||||
val enc = prefs.getString("mib_enc_app_id", null) ?: return null
|
||||
return try { decrypt(enc, key) } catch (_: Exception) { null }
|
||||
}
|
||||
|
||||
// ── BML login credentials ─────────────────────────────────────────────────
|
||||
|
||||
fun saveBmlCredentials(username: String, password: String, otpSeed: String) {
|
||||
val key = getOrCreateKey()
|
||||
prefs.edit()
|
||||
@@ -71,7 +107,7 @@ class CredentialStore(context: Context) {
|
||||
val encSeed = prefs.getString("bml_enc_otp_seed", null) ?: return null
|
||||
return try {
|
||||
BmlCredentials(decrypt(encUsername, key), decrypt(encPassword, key), decrypt(encSeed, key))
|
||||
} catch (e: Exception) { null }
|
||||
} catch (_: Exception) { null }
|
||||
}
|
||||
|
||||
fun clearBmlCredentials() {
|
||||
@@ -82,6 +118,8 @@ class CredentialStore(context: Context) {
|
||||
.apply()
|
||||
}
|
||||
|
||||
// ── BML session token ─────────────────────────────────────────────────────
|
||||
|
||||
fun saveBmlSession(accessToken: String, deviceId: String) {
|
||||
val key = getOrCreateKey()
|
||||
prefs.edit()
|
||||
@@ -106,6 +144,39 @@ class CredentialStore(context: Context) {
|
||||
.apply()
|
||||
}
|
||||
|
||||
// ── Security credential (PIN / pattern hash) ──────────────────────────────
|
||||
|
||||
/**
|
||||
* Stores the PBKDF2-derived hash and its salt, encrypted with the AndroidKeyStore key.
|
||||
* The lock method ("pin"/"pattern") remains in the app's "prefs" SharedPreferences and
|
||||
* is not stored here.
|
||||
*/
|
||||
fun saveSecurityHash(salt: String, hash: String) {
|
||||
val key = getOrCreateKey()
|
||||
prefs.edit()
|
||||
.putString("security_enc_salt", encrypt(salt, key))
|
||||
.putString("security_enc_hash", encrypt(hash, key))
|
||||
.apply()
|
||||
}
|
||||
|
||||
fun loadSecurityHash(): Pair<String, String>? {
|
||||
val key = getOrCreateKey()
|
||||
val encSalt = prefs.getString("security_enc_salt", null) ?: return null
|
||||
val encHash = prefs.getString("security_enc_hash", null) ?: return null
|
||||
return try {
|
||||
Pair(decrypt(encSalt, key), decrypt(encHash, key))
|
||||
} catch (_: Exception) { null }
|
||||
}
|
||||
|
||||
fun clearSecurityHash() {
|
||||
prefs.edit()
|
||||
.remove("security_enc_salt")
|
||||
.remove("security_enc_hash")
|
||||
.apply()
|
||||
}
|
||||
|
||||
// ── User profile (PII) ────────────────────────────────────────────────────
|
||||
|
||||
data class MibUserProfile(
|
||||
val fullName: String,
|
||||
val username: String,
|
||||
@@ -123,54 +194,89 @@ class CredentialStore(context: Context) {
|
||||
val birthdate: String
|
||||
)
|
||||
|
||||
fun saveMibFullName(name: String) = prefs.edit().putString("mib_full_name", name).apply()
|
||||
fun loadMibFullName(): String? = prefs.getString("mib_full_name", null)
|
||||
fun saveMibFullName(name: String) {
|
||||
val key = getOrCreateKey()
|
||||
prefs.edit().putString("mib_enc_full_name", encrypt(name, key)).apply()
|
||||
}
|
||||
|
||||
fun saveBmlFullName(name: String) = prefs.edit().putString("bml_full_name", name).apply()
|
||||
fun loadBmlFullName(): String? = prefs.getString("bml_full_name", null)
|
||||
fun loadMibFullName(): String? {
|
||||
val key = getOrCreateKey()
|
||||
val enc = prefs.getString("mib_enc_full_name", null) ?: return null
|
||||
return try { decrypt(enc, key) } catch (_: Exception) { null }
|
||||
}
|
||||
|
||||
fun saveBmlFullName(name: String) {
|
||||
val key = getOrCreateKey()
|
||||
prefs.edit().putString("bml_enc_full_name", encrypt(name, key)).apply()
|
||||
}
|
||||
|
||||
fun loadBmlFullName(): String? {
|
||||
val key = getOrCreateKey()
|
||||
val enc = prefs.getString("bml_enc_full_name", null) ?: return null
|
||||
return try { decrypt(enc, key) } catch (_: Exception) { null }
|
||||
}
|
||||
|
||||
fun saveMibUserProfile(p: MibUserProfile) {
|
||||
prefs.edit().putString("mib_full_name", p.fullName)
|
||||
.putString("mib_profile_username", p.username)
|
||||
.putString("mib_profile_email", p.email)
|
||||
.putString("mib_profile_mobile", p.mobile)
|
||||
.putString("mib_profile_enrolled", p.enrolled)
|
||||
.apply()
|
||||
val json = JSONObject().apply {
|
||||
put("fullName", p.fullName)
|
||||
put("username", p.username)
|
||||
put("email", p.email)
|
||||
put("mobile", p.mobile)
|
||||
put("enrolled", p.enrolled)
|
||||
}.toString()
|
||||
val key = getOrCreateKey()
|
||||
prefs.edit().putString("mib_enc_profile", encrypt(json, key)).apply()
|
||||
// Keep the name in sync with the fast-path field
|
||||
prefs.edit().putString("mib_enc_full_name", encrypt(p.fullName, key)).apply()
|
||||
}
|
||||
|
||||
fun loadMibUserProfile(): MibUserProfile? {
|
||||
val name = prefs.getString("mib_full_name", null) ?: return null
|
||||
return MibUserProfile(
|
||||
fullName = name,
|
||||
username = prefs.getString("mib_profile_username", "") ?: "",
|
||||
email = prefs.getString("mib_profile_email", "") ?: "",
|
||||
mobile = prefs.getString("mib_profile_mobile", "") ?: "",
|
||||
enrolled = prefs.getString("mib_profile_enrolled", "") ?: ""
|
||||
)
|
||||
val key = getOrCreateKey()
|
||||
val enc = prefs.getString("mib_enc_profile", null) ?: return null
|
||||
return try {
|
||||
val o = JSONObject(decrypt(enc, key))
|
||||
MibUserProfile(
|
||||
fullName = o.optString("fullName"),
|
||||
username = o.optString("username"),
|
||||
email = o.optString("email"),
|
||||
mobile = o.optString("mobile"),
|
||||
enrolled = o.optString("enrolled")
|
||||
)
|
||||
} catch (_: Exception) { null }
|
||||
}
|
||||
|
||||
fun saveBmlUserProfile(p: BmlUserProfile) {
|
||||
prefs.edit().putString("bml_full_name", p.fullName)
|
||||
.putString("bml_profile_email", p.email)
|
||||
.putString("bml_profile_mobile", p.mobile)
|
||||
.putString("bml_profile_customer_id", p.customerId)
|
||||
.putString("bml_profile_idcard", p.idCard)
|
||||
.putString("bml_profile_birthdate", p.birthdate)
|
||||
.apply()
|
||||
val json = JSONObject().apply {
|
||||
put("fullName", p.fullName)
|
||||
put("email", p.email)
|
||||
put("mobile", p.mobile)
|
||||
put("customerId", p.customerId)
|
||||
put("idCard", p.idCard)
|
||||
put("birthdate", p.birthdate)
|
||||
}.toString()
|
||||
val key = getOrCreateKey()
|
||||
prefs.edit().putString("bml_enc_profile", encrypt(json, key)).apply()
|
||||
prefs.edit().putString("bml_enc_full_name", encrypt(p.fullName, key)).apply()
|
||||
}
|
||||
|
||||
fun loadBmlUserProfile(): BmlUserProfile? {
|
||||
val name = prefs.getString("bml_full_name", null) ?: return null
|
||||
return BmlUserProfile(
|
||||
fullName = name,
|
||||
email = prefs.getString("bml_profile_email", "") ?: "",
|
||||
mobile = prefs.getString("bml_profile_mobile", "") ?: "",
|
||||
customerId = prefs.getString("bml_profile_customer_id", "") ?: "",
|
||||
idCard = prefs.getString("bml_profile_idcard", "") ?: "",
|
||||
birthdate = prefs.getString("bml_profile_birthdate", "") ?: ""
|
||||
)
|
||||
val key = getOrCreateKey()
|
||||
val enc = prefs.getString("bml_enc_profile", null) ?: return null
|
||||
return try {
|
||||
val o = JSONObject(decrypt(enc, key))
|
||||
BmlUserProfile(
|
||||
fullName = o.optString("fullName"),
|
||||
email = o.optString("email"),
|
||||
mobile = o.optString("mobile"),
|
||||
customerId = o.optString("customerId"),
|
||||
idCard = o.optString("idCard"),
|
||||
birthdate = o.optString("birthdate")
|
||||
)
|
||||
} catch (_: Exception) { null }
|
||||
}
|
||||
|
||||
// ── Crypto primitives ─────────────────────────────────────────────────────
|
||||
|
||||
private fun getOrCreateKey(): SecretKey {
|
||||
val ks = KeyStore.getInstance("AndroidKeyStore").also { it.load(null) }
|
||||
ks.getKey(keyAlias, null)?.let { return it as SecretKey }
|
||||
@@ -193,16 +299,16 @@ class CredentialStore(context: Context) {
|
||||
val cipher = Cipher.getInstance(transformation)
|
||||
cipher.init(Cipher.ENCRYPT_MODE, key)
|
||||
val iv = cipher.iv
|
||||
val ct = cipher.doFinal(plaintext.toByteArray())
|
||||
val ct = cipher.doFinal(plaintext.toByteArray(Charsets.UTF_8))
|
||||
return Base64.encodeToString(iv, Base64.NO_WRAP) + ":" + Base64.encodeToString(ct, Base64.NO_WRAP)
|
||||
}
|
||||
|
||||
private fun decrypt(encoded: String, key: SecretKey): String {
|
||||
val parts = encoded.split(":")
|
||||
val iv = Base64.decode(parts[0], Base64.NO_WRAP)
|
||||
val ct = Base64.decode(parts[1], Base64.NO_WRAP)
|
||||
val colon = encoded.indexOf(':')
|
||||
val iv = Base64.decode(encoded.substring(0, colon), Base64.NO_WRAP)
|
||||
val ct = Base64.decode(encoded.substring(colon + 1), Base64.NO_WRAP)
|
||||
val cipher = Cipher.getInstance(transformation)
|
||||
cipher.init(Cipher.DECRYPT_MODE, key, GCMParameterSpec(128, iv))
|
||||
return String(cipher.doFinal(ct))
|
||||
return String(cipher.doFinal(ct), Charsets.UTF_8)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -31,7 +31,7 @@ object FinancingCache {
|
||||
})
|
||||
}
|
||||
context.getSharedPreferences(PREFS, Context.MODE_PRIVATE)
|
||||
.edit().putString(KEY_MIB, arr.toString()).apply()
|
||||
.edit().putString(KEY_MIB, CacheEncryption.encrypt(arr.toString())).apply()
|
||||
}
|
||||
|
||||
fun clear(context: Context) {
|
||||
@@ -39,9 +39,10 @@ object FinancingCache {
|
||||
}
|
||||
|
||||
fun load(context: Context): List<MibFinanceDeal> {
|
||||
val json = context.getSharedPreferences(PREFS, Context.MODE_PRIVATE)
|
||||
val raw = context.getSharedPreferences(PREFS, Context.MODE_PRIVATE)
|
||||
.getString(KEY_MIB, null) ?: return emptyList()
|
||||
return try {
|
||||
val json = CacheEncryption.decrypt(raw)
|
||||
val arr = JSONArray(json)
|
||||
(0 until arr.length()).map { i ->
|
||||
val o = arr.getJSONObject(i)
|
||||
|
||||
@@ -39,7 +39,7 @@ object ForeignLimitsCache {
|
||||
})
|
||||
}
|
||||
context.getSharedPreferences(PREFS, Context.MODE_PRIVATE)
|
||||
.edit().putString(KEY, arr.toString()).apply()
|
||||
.edit().putString(KEY, CacheEncryption.encrypt(arr.toString())).apply()
|
||||
}
|
||||
|
||||
fun clear(context: Context) {
|
||||
@@ -47,9 +47,10 @@ object ForeignLimitsCache {
|
||||
}
|
||||
|
||||
fun load(context: Context): List<HomeViewModel.BmlLimitsData> {
|
||||
val json = context.getSharedPreferences(PREFS, Context.MODE_PRIVATE)
|
||||
val raw = context.getSharedPreferences(PREFS, Context.MODE_PRIVATE)
|
||||
.getString(KEY, null) ?: return emptyList()
|
||||
return try {
|
||||
val json = CacheEncryption.decrypt(raw)
|
||||
val arr = JSONArray(json)
|
||||
(0 until arr.length()).map { i ->
|
||||
val entry = arr.getJSONObject(i)
|
||||
|
||||
@@ -37,7 +37,7 @@ object RecentsCache {
|
||||
})
|
||||
}
|
||||
context.getSharedPreferences(PREFS, Context.MODE_PRIVATE)
|
||||
.edit().putString(KEY, arr.toString()).apply()
|
||||
.edit().putString(KEY, CacheEncryption.encrypt(arr.toString())).apply()
|
||||
}
|
||||
|
||||
fun remove(context: Context, accountNumber: String) {
|
||||
@@ -54,7 +54,7 @@ object RecentsCache {
|
||||
})
|
||||
}
|
||||
context.getSharedPreferences(PREFS, Context.MODE_PRIVATE)
|
||||
.edit().putString(KEY, arr.toString()).apply()
|
||||
.edit().putString(KEY, CacheEncryption.encrypt(arr.toString())).apply()
|
||||
}
|
||||
|
||||
fun clear(context: Context) {
|
||||
@@ -62,9 +62,10 @@ object RecentsCache {
|
||||
}
|
||||
|
||||
fun load(context: Context): List<RecentPick> {
|
||||
val json = context.getSharedPreferences(PREFS, Context.MODE_PRIVATE)
|
||||
val raw = context.getSharedPreferences(PREFS, Context.MODE_PRIVATE)
|
||||
.getString(KEY, null) ?: return emptyList()
|
||||
return try {
|
||||
val json = CacheEncryption.decrypt(raw)
|
||||
val arr = JSONArray(json)
|
||||
(0 until arr.length()).map { i ->
|
||||
val o = arr.getJSONObject(i)
|
||||
|
||||
Reference in New Issue
Block a user