-
Notifications
You must be signed in to change notification settings - Fork 1k
PM-37879: feat: Add SDK state bridge #7204
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. Weβll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: main
Are you sure you want to change the base?
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,137 @@ | ||
| package com.x8bit.bitwarden.data.platform.manager.sdk.statebridge | ||
|
|
||
| import com.bitwarden.core.MasterPasswordUnlockData | ||
| import com.bitwarden.core.StateBridgeForeignImpl | ||
| import com.bitwarden.core.V2UpgradeToken | ||
| import com.bitwarden.core.WrappedAccountCryptographicState | ||
| import com.bitwarden.crypto.EncString | ||
| import com.bitwarden.crypto.PasswordProtectedKeyEnvelope | ||
| import com.bitwarden.crypto.SymmetricCryptoKey | ||
| import com.x8bit.bitwarden.data.auth.datasource.disk.AuthDiskSource | ||
| import com.x8bit.bitwarden.data.auth.repository.util.updateMasterPasswordUnlock | ||
| import com.x8bit.bitwarden.data.vault.repository.util.toSdkMasterPasswordUnlock | ||
| import com.x8bit.bitwarden.data.vault.repository.util.toV2UpgradeToken | ||
| import com.x8bit.bitwarden.data.vault.repository.util.toV2UpgradeTokenJson | ||
|
|
||
| /** | ||
| * A user-scoped implementation of a Bitwarden SDK [StateBridgeForeignImpl]. | ||
| */ | ||
| @Suppress("TooManyFunctions") | ||
| internal class SdkStateBridge( | ||
| private val userId: String, | ||
| private val authDiskSource: AuthDiskSource, | ||
| ) : StateBridgeForeignImpl { | ||
| @Volatile | ||
| private var inMemoryUserKey: SymmetricCryptoKey? = null | ||
|
|
||
| override suspend fun setUserKey(value: SymmetricCryptoKey) { | ||
| inMemoryUserKey = value | ||
| } | ||
|
|
||
| override suspend fun getUserKey(): SymmetricCryptoKey? = inMemoryUserKey | ||
|
|
||
| override suspend fun clearUserKey() { | ||
| inMemoryUserKey = null | ||
| } | ||
|
|
||
| override suspend fun setPersistentPinEnvelope(value: PasswordProtectedKeyEnvelope) { | ||
| authDiskSource.storePersistentPinProtectedUserKeyEnvelope( | ||
| userId = userId, | ||
| pinProtectedUserKeyEnvelope = value, | ||
| ) | ||
| } | ||
|
|
||
| override suspend fun getPersistentPinEnvelope(): PasswordProtectedKeyEnvelope? = | ||
| authDiskSource.getPersistentPinProtectedUserKeyEnvelope(userId = userId) | ||
|
|
||
| override suspend fun clearPersistentPinEnvelope() { | ||
| authDiskSource.storePersistentPinProtectedUserKeyEnvelope( | ||
| userId = userId, | ||
| pinProtectedUserKeyEnvelope = null, | ||
| ) | ||
| } | ||
|
|
||
| override suspend fun setEphemeralPinEnvelope(value: PasswordProtectedKeyEnvelope) { | ||
| authDiskSource.storeEphemeralPinProtectedUserKeyEnvelope( | ||
| userId = userId, | ||
| pinProtectedUserKeyEnvelope = value, | ||
| ) | ||
| } | ||
|
|
||
| override suspend fun getEphemeralPinEnvelope(): PasswordProtectedKeyEnvelope? = | ||
| authDiskSource.getEphemeralPinProtectedUserKeyEnvelope(userId = userId) | ||
|
|
||
| override suspend fun clearEphemeralPinEnvelope() { | ||
| authDiskSource.storeEphemeralPinProtectedUserKeyEnvelope( | ||
| userId = userId, | ||
| pinProtectedUserKeyEnvelope = null, | ||
| ) | ||
| } | ||
|
|
||
| override suspend fun setEncryptedPin(value: EncString) { | ||
| authDiskSource.storeEncryptedPin(userId = userId, encryptedPin = value) | ||
| } | ||
|
|
||
| override suspend fun getEncryptedPin(): EncString? = | ||
| authDiskSource.getEncryptedPin(userId = userId) | ||
|
|
||
| override suspend fun clearEncryptedPin() { | ||
| authDiskSource.storeEncryptedPin(userId = userId, encryptedPin = null) | ||
| } | ||
|
|
||
| override suspend fun setV2UpgradeToken(value: V2UpgradeToken) { | ||
| authDiskSource.storeV2UpgradeToken( | ||
| userId = userId, | ||
| v2UpgradeToken = value.toV2UpgradeTokenJson(), | ||
| ) | ||
| } | ||
|
|
||
| override suspend fun getV2UpgradeToken(): V2UpgradeToken? = | ||
| authDiskSource | ||
| .getV2UpgradeToken(userId = userId) | ||
| ?.toV2UpgradeToken() | ||
|
|
||
| override suspend fun clearV2UpgradeToken() { | ||
| authDiskSource.storeV2UpgradeToken(userId = userId, v2UpgradeToken = null) | ||
| } | ||
|
|
||
| override suspend fun setAccountCryptographicState(value: WrappedAccountCryptographicState) { | ||
| authDiskSource.storeAccountCryptographicState( | ||
| userId = userId, | ||
| accountCryptographicState = value, | ||
| ) | ||
| } | ||
|
|
||
| override suspend fun getAccountCryptographicState(): WrappedAccountCryptographicState? = | ||
| authDiskSource.getAccountCryptographicState(userId = userId) | ||
|
|
||
| override suspend fun clearAccountCryptographicState() { | ||
| authDiskSource.storeAccountCryptographicState( | ||
| userId = userId, | ||
| accountCryptographicState = null, | ||
| ) | ||
| } | ||
|
|
||
| override suspend fun setMasterpasswordUnlockData(value: MasterPasswordUnlockData) { | ||
| authDiskSource.userState = authDiskSource.userState?.updateMasterPasswordUnlock( | ||
| userId = userId, | ||
| masterPasswordUnlock = value, | ||
| ) | ||
| } | ||
|
Comment on lines
+115
to
+120
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
Details and fix
Nothing restores the flag afterwards: on sync, Consider a helper that updates only Related: |
||
|
|
||
| override suspend fun getMasterpasswordUnlockData(): MasterPasswordUnlockData? = | ||
| authDiskSource | ||
| .userState | ||
| ?.accounts[userId] | ||
| ?.profile | ||
| ?.userDecryptionOptions | ||
| ?.masterPasswordUnlock | ||
| ?.toSdkMasterPasswordUnlock() | ||
|
|
||
| override suspend fun clearMasterpasswordUnlockData() { | ||
| authDiskSource.userState = authDiskSource.userState?.updateMasterPasswordUnlock( | ||
| userId = userId, | ||
| masterPasswordUnlock = null, | ||
| ) | ||
| } | ||
| } | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,22 @@ | ||
| package com.x8bit.bitwarden.data.vault.repository.util | ||
|
|
||
| import com.bitwarden.core.V2UpgradeToken | ||
| import com.bitwarden.network.model.V2UpgradeTokenJson | ||
|
|
||
| /** | ||
| * Converts the [V2UpgradeToken] into a [V2UpgradeTokenJson]. | ||
| */ | ||
| fun V2UpgradeToken.toV2UpgradeTokenJson(): V2UpgradeTokenJson = | ||
| V2UpgradeTokenJson( | ||
| wrappedUserKey1 = this.wrappedUserKey1, | ||
| wrappedUserKey2 = this.wrappedUserKey2, | ||
| ) | ||
|
|
||
| /** | ||
| * Converts the [V2UpgradeTokenJson] into a [V2UpgradeToken]. | ||
| */ | ||
| fun V2UpgradeTokenJson.toV2UpgradeToken(): V2UpgradeToken = | ||
| V2UpgradeToken( | ||
| wrappedUserKey1 = this.wrappedUserKey1, | ||
| wrappedUserKey2 = this.wrappedUserKey2, | ||
| ) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
If we have a updateMasterPasswordUnlock function here, why not also make a getMasterPasswordUnlock, instead of having the log
.chain in the get below?There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Setting the data is a more complicated process that we want abstracted for reusability, fetching the data is not particularly complicated, so we never bothered to abstract it.
For whatever it's worth, I am working on migrating the master password unlock data out of the
userState. Once that work is done, they with both be simple get and set functions on theauthDiskSource.