Skip to content

Commit

Permalink
[PM-17424] Implement disk data source for key data
Browse files Browse the repository at this point in the history
This commit introduces a new disk data source, `KeyDiskSource`, for managing key-related data.
This includes:
- Storing the alias and host of the selected mTLS key.
- Retrieving the alias and host of the selected mTLS key.

A default implementation, `KeyDiskSourceImpl`, is provided using encrypted shared preferences to securely store the key data.
The `PlatformDiskModule` is updated to provide an instance of `KeyDiskSource`.
  • Loading branch information
SaintPatrck committed Jan 21, 2025
1 parent bb5aeaa commit 5e37666
Show file tree
Hide file tree
Showing 5 changed files with 161 additions and 0 deletions.
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
package com.x8bit.bitwarden.data.platform.datasource.disk

import com.x8bit.bitwarden.data.platform.datasource.disk.model.MutualTlsKeyHost

/**
* Primary access point for disk information related to key data.
*/
interface KeyDiskSource {

/**
* Sets the alias and host of the selected mTLS key.
*/
fun storeMutualTlsKey(
userId: String,
alias: String?,
host: MutualTlsKeyHost?,
)

/**
* Alias of the mTLS key if one is selected.
*/
fun getMutualTlsKeyAlias(userId: String): String?

/**
* Host of the mTLS key if one is selected.
*/
fun getMutualTlsKeyHost(userId: String): MutualTlsKeyHost?
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
package com.x8bit.bitwarden.data.platform.datasource.disk

import android.content.SharedPreferences
import com.x8bit.bitwarden.data.platform.datasource.disk.model.MutualTlsKeyHost

private const val MUTUAL_TLS_KEY_ALIAS = "mutualTlsKeyAlias"
private const val MUTUAL_TLS_KEY_HOST = "mutualTlsKeyHost"

/**
* Default implementation of [KeyDiskSource].
*/
class KeyDiskSourceImpl(
encryptedPreferences: SharedPreferences,
sharedPreferences: SharedPreferences,
) : BaseEncryptedDiskSource(
sharedPreferences = sharedPreferences,
encryptedSharedPreferences = encryptedPreferences,
), KeyDiskSource {

override fun storeMutualTlsKey(
userId: String,
alias: String?,
host: MutualTlsKeyHost?,
) {
putEncryptedString(
key = MUTUAL_TLS_KEY_ALIAS.appendIdentifier(userId),
value = alias,
)
}

override fun getMutualTlsKeyAlias(userId: String): String? =
getEncryptedString(key = MUTUAL_TLS_KEY_ALIAS.appendIdentifier(userId))

override fun getMutualTlsKeyHost(userId: String): MutualTlsKeyHost? =
getEncryptedString(MUTUAL_TLS_KEY_HOST.appendIdentifier(userId))
?.let { MutualTlsKeyHost.valueOf(it) }
}
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,8 @@ import com.x8bit.bitwarden.data.platform.datasource.disk.EventDiskSource
import com.x8bit.bitwarden.data.platform.datasource.disk.EventDiskSourceImpl
import com.x8bit.bitwarden.data.platform.datasource.disk.FeatureFlagOverrideDiskSource
import com.x8bit.bitwarden.data.platform.datasource.disk.FeatureFlagOverrideDiskSourceImpl
import com.x8bit.bitwarden.data.platform.datasource.disk.KeyDiskSource
import com.x8bit.bitwarden.data.platform.datasource.disk.KeyDiskSourceImpl
import com.x8bit.bitwarden.data.platform.datasource.disk.PushDiskSource
import com.x8bit.bitwarden.data.platform.datasource.disk.PushDiskSourceImpl
import com.x8bit.bitwarden.data.platform.datasource.disk.SettingsDiskSource
Expand Down Expand Up @@ -165,4 +167,15 @@ object PlatformDiskModule {
): FeatureFlagOverrideDiskSource = FeatureFlagOverrideDiskSourceImpl(
sharedPreferences = sharedPreferences,
)

@Provides
@Singleton
fun provideKeyDiskSource(
@UnencryptedPreferences sharedPreferences: SharedPreferences,
@EncryptedPreferences encryptedSharedPreferences: SharedPreferences,
): KeyDiskSource =
KeyDiskSourceImpl(
sharedPreferences = sharedPreferences,
encryptedPreferences = encryptedSharedPreferences,
)
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
package com.x8bit.bitwarden.data.platform.datasource.disk.model

/**
* Location of the key data.
*/
enum class MutualTlsKeyHost {
/**
* Key is stored in the system key chain.
*/
KEY_CHAIN,

/**
* Key is stored in a private instance of the Android Key Store.
*/
ANDROID_KEY_STORE,
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,67 @@
package com.x8bit.bitwarden.data.platform.datasource.disk

import androidx.core.content.edit
import com.x8bit.bitwarden.data.platform.base.FakeSharedPreferences
import com.x8bit.bitwarden.data.platform.datasource.disk.model.MutualTlsKeyHost
import org.junit.jupiter.api.Assertions.assertEquals
import org.junit.jupiter.api.Assertions.assertNull
import org.junit.jupiter.api.Test

class KeyDiskSourceTest {
private val fakeEncryptedSharedPreferences = FakeSharedPreferences()
private val fakeSharedPreferences = FakeSharedPreferences()

private val keyDiskSource = KeyDiskSourceImpl(
sharedPreferences = fakeSharedPreferences,
encryptedPreferences = fakeEncryptedSharedPreferences,
)

@Test
fun `storeMutualTlsKey should update encrypted SharedPreferences`() {
val certificateAliasBaseKey = "bwSecureStorage:mutualTlsKeyAlias"
val certificateHostBaseKey = "bwSecureStorage:mutualTlsKeyHost"
val mockUserId = "mockUserId"
val mockAlias = "mockCertificateAlias"
val mockHost = MutualTlsKeyHost.ANDROID_KEY_STORE

// Verify that the SharedPreferences are initialized empty
assertNull(
fakeEncryptedSharedPreferences
.getString(
"${certificateAliasBaseKey}_$mockUserId",
null,
),
)
assertNull(
fakeEncryptedSharedPreferences
.getString(
"${certificateHostBaseKey}_$mockUserId",
null,
),
)

fakeEncryptedSharedPreferences
.edit {
putString(
"${certificateAliasBaseKey}_$mockUserId",
mockAlias,
)
putString(
"${certificateHostBaseKey}_$mockUserId",
mockHost.name,
)
}

// Verify alias and host are updated in SharedPreferences
val alias = keyDiskSource.getMutualTlsKeyAlias(userId = mockUserId)
val host = keyDiskSource.getMutualTlsKeyHost(userId = mockUserId)
assertEquals(
mockAlias,
alias,
)
assertEquals(
mockHost,
host,
)
}
}

0 comments on commit 5e37666

Please sign in to comment.