mirror of
https://github.com/bitwarden/android.git
synced 2024-10-31 15:15:34 +03:00
Add persistence for PIN-unlock related data (#611)
This commit is contained in:
parent
76b04a849d
commit
6a208fee31
4 changed files with 146 additions and 0 deletions
|
@ -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.
|
||||
|
|
|
@ -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) }
|
||||
|
|
|
@ -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"
|
||||
|
|
|
@ -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]
|
||||
|
|
Loading…
Reference in a new issue