Add persistence for PIN-unlock related data (#611)

This commit is contained in:
Brian Yencho 2024-01-14 16:56:42 -06:00 committed by Álison Fernandes
parent 76b04a849d
commit 6a208fee31
4 changed files with 146 additions and 0 deletions

View file

@ -87,6 +87,26 @@ interface AuthDiskSource {
*/
fun storeUserAutoUnlockKey(userId: String, userAutoUnlockKey: String?)
/**
* Retrieves a pin-protected user key for the given [userId].
*/
fun getPinProtectedUserKey(userId: String): String?
/**
* Stores a pin-protected user key for the given [userId].
*/
fun storePinProtectedUserKey(userId: String, pinProtectedUserKey: String?)
/**
* Retrieves an encrypted PIN for the given [userId].
*/
fun getEncryptedPin(userId: String): String?
/**
* Stores an encrypted PIN for the given [userId].
*/
fun storeEncryptedPin(userId: String, encryptedPin: String?)
/**
* Gets the organization keys for the given [userId] in the form of a mapping from organization
* ID to encrypted organization key.

View file

@ -22,6 +22,8 @@ private const val STATE_KEY = "$BASE_KEY:state"
private const val LAST_ACTIVE_TIME_KEY = "$BASE_KEY:lastActiveTime"
private const val MASTER_KEY_ENCRYPTION_USER_KEY = "$BASE_KEY:masterKeyEncryptedUserKey"
private const val MASTER_KEY_ENCRYPTION_PRIVATE_KEY = "$BASE_KEY:encPrivateKey"
private const val PIN_PROTECTED_USER_KEY_KEY = "$BASE_KEY:pinKeyEncryptedUserKey"
private const val ENCRYPTED_PIN_KEY = "$BASE_KEY:protectedPin"
private const val ORGANIZATIONS_KEY = "$BASE_KEY:organizations"
private const val ORGANIZATION_KEYS_KEY = "$BASE_KEY:encOrgKeys"
@ -73,6 +75,8 @@ class AuthDiskSourceImpl(
storeLastActiveTimeMillis(userId = userId, lastActiveTimeMillis = null)
storeUserKey(userId = userId, userKey = null)
storeUserAutoUnlockKey(userId = userId, userAutoUnlockKey = null)
storePinProtectedUserKey(userId = userId, pinProtectedUserKey = null)
storeEncryptedPin(userId = userId, encryptedPin = null)
storePrivateKey(userId = userId, privateKey = null)
storeOrganizationKeys(userId = userId, organizationKeys = null)
storeOrganizations(userId = userId, organizations = null)
@ -127,6 +131,32 @@ class AuthDiskSourceImpl(
)
}
override fun getPinProtectedUserKey(userId: String): String? =
getString(key = "${PIN_PROTECTED_USER_KEY_KEY}_$userId")
override fun storePinProtectedUserKey(
userId: String,
pinProtectedUserKey: String?,
) {
putString(
key = "${PIN_PROTECTED_USER_KEY_KEY}_$userId",
value = pinProtectedUserKey,
)
}
override fun getEncryptedPin(userId: String): String? =
getString(key = "${ENCRYPTED_PIN_KEY}_$userId")
override fun storeEncryptedPin(
userId: String,
encryptedPin: String?,
) {
putString(
key = "${ENCRYPTED_PIN_KEY}_$userId",
value = encryptedPin,
)
}
override fun getOrganizationKeys(userId: String): Map<String, String>? =
getString(key = "${ORGANIZATION_KEYS_KEY}_$userId")
?.let { json.decodeFromString(it) }

View file

@ -324,6 +324,84 @@ class AuthDiskSourceTest {
)
}
@Test
fun `getPinProtectedUserKey should pull from SharedPreferences`() {
val pinProtectedUserKeyBaseKey = "bwPreferencesStorage:pinKeyEncryptedUserKey"
val mockUserId = "mockUserId"
val mockPinProtectedUserKey = "mockPinProtectedUserKey"
fakeSharedPreferences
.edit()
.putString(
"${pinProtectedUserKeyBaseKey}_$mockUserId",
mockPinProtectedUserKey,
)
.apply()
val actual = authDiskSource.getPinProtectedUserKey(userId = mockUserId)
assertEquals(
mockPinProtectedUserKey,
actual,
)
}
@Test
fun `storePinProtectedUserKey should update SharedPreferences`() {
val pinProtectedUserKeyBaseKey = "bwPreferencesStorage:pinKeyEncryptedUserKey"
val mockUserId = "mockUserId"
val mockPinProtectedUserKey = "mockPinProtectedUserKey"
authDiskSource.storePinProtectedUserKey(
userId = mockUserId,
pinProtectedUserKey = mockPinProtectedUserKey,
)
val actual = fakeSharedPreferences
.getString(
"${pinProtectedUserKeyBaseKey}_$mockUserId",
null,
)
assertEquals(
mockPinProtectedUserKey,
actual,
)
}
@Test
fun `getEncryptedPin should pull from SharedPreferences`() {
val encryptedPinBaseKey = "bwPreferencesStorage:protectedPin"
val mockUserId = "mockUserId"
val mockEncryptedPin = "mockEncryptedPin"
fakeSharedPreferences
.edit()
.putString(
"${encryptedPinBaseKey}_$mockUserId",
mockEncryptedPin,
)
.apply()
val actual = authDiskSource.getEncryptedPin(userId = mockUserId)
assertEquals(
mockEncryptedPin,
actual,
)
}
@Test
fun `storeEncryptedPin should update SharedPreferences`() {
val encryptedPinBaseKey = "bwPreferencesStorage:protectedPin"
val mockUserId = "mockUserId"
val mockEncryptedPin = "mockUserAutoUnlockKey"
authDiskSource.storeEncryptedPin(
userId = mockUserId,
encryptedPin = mockEncryptedPin,
)
val actual = fakeSharedPreferences
.getString(
"${encryptedPinBaseKey}_$mockUserId",
null,
)
assertEquals(
mockEncryptedPin,
actual,
)
}
@Test
fun `getOrganizationKeys should pull from SharedPreferences`() {
val organizationKeysBaseKey = "bwPreferencesStorage:encOrgKeys"

View file

@ -23,6 +23,8 @@ class FakeAuthDiskSource : AuthDiskSource {
private val storedUserKeys = mutableMapOf<String, String?>()
private val storedPrivateKeys = mutableMapOf<String, String?>()
private val storedUserAutoUnlockKeys = mutableMapOf<String, String?>()
private val storedPinProtectedUserKeys = mutableMapOf<String, String?>()
private val storedEncryptedPins = mutableMapOf<String, String?>()
private val storedOrganizations =
mutableMapOf<String, List<SyncResponseJson.Profile.Organization>?>()
private val storedOrganizationKeys = mutableMapOf<String, Map<String, String>?>()
@ -41,6 +43,8 @@ class FakeAuthDiskSource : AuthDiskSource {
storedUserKeys.remove(userId)
storedPrivateKeys.remove(userId)
storedUserAutoUnlockKeys.remove(userId)
storedPinProtectedUserKeys.remove(userId)
storedEncryptedPins.remove(userId)
storedOrganizations.remove(userId)
storedOrganizationKeys.remove(userId)
@ -76,6 +80,20 @@ class FakeAuthDiskSource : AuthDiskSource {
storedUserAutoUnlockKeys[userId] = userAutoUnlockKey
}
override fun getPinProtectedUserKey(userId: String): String? =
storedPinProtectedUserKeys[userId]
override fun storePinProtectedUserKey(userId: String, pinProtectedUserKey: String?) {
storedPinProtectedUserKeys[userId] = pinProtectedUserKey
}
override fun getEncryptedPin(userId: String): String? =
storedEncryptedPins[userId]
override fun storeEncryptedPin(userId: String, encryptedPin: String?) {
storedEncryptedPins[userId] = encryptedPin
}
override fun getOrganizationKeys(
userId: String,
): Map<String, String>? = storedOrganizationKeys[userId]