BITAU-112 Support deep link into add item flow from Authenticator app (#4128)

This commit is contained in:
Andrew Haisting
2024-10-23 11:17:31 -05:00
committed by GitHub
parent f1d7d1a530
commit fa248243b6
15 changed files with 365 additions and 21 deletions

View File

@@ -49,13 +49,8 @@ interface IAuthenticatorBridgeService {
// Add TOTP Item
// ==============
// Returns an intent that can be launched to navigate the user to the add Totp item flow
// in the main password manager app.
Intent createAddTotpLoginItemIntent();
// Give the given TOTP item data to the main Bitwarden app before launching the add TOTP
// item flow. This should be called before launching the intent returned from
// createAddTotpLoginItemIntent().
void setPendingAddTotpLoginItemData(in EncryptedAddTotpLoginItemData data);
// Start the add TOTP item flow in the main Bitwarden app with the given data.
// Returns true if the flow was successfully launched and false otherwise.
boolean startAddTotpLoginItemFlow(in EncryptedAddTotpLoginItemData data);
}

View File

@@ -1,5 +1,7 @@
package com.bitwarden.authenticatorbridge.manager
import android.content.Intent
import android.net.Uri
import com.bitwarden.authenticatorbridge.IAuthenticatorBridgeService
import com.bitwarden.authenticatorbridge.manager.model.AccountSyncState
import kotlinx.coroutines.flow.StateFlow
@@ -14,4 +16,12 @@ interface AuthenticatorBridgeManager {
* State flow representing the current [AccountSyncState].
*/
val accountSyncStateFlow: StateFlow<AccountSyncState>
/**
* Start the add TOTP item flow in the main Bitwarden app with the given data.
*
* @param totpUri TOTP URI to add to the main Bitwarden app.
* @return true if the flow was successfully launched, false otherwise.
*/
fun startAddTotpLoginItemFlow(totpUri: String): Boolean
}

View File

@@ -7,6 +7,7 @@ import android.content.ServiceConnection
import android.content.pm.PackageManager.NameNotFoundException
import android.os.Build
import android.os.IBinder
import android.util.Log
import androidx.lifecycle.DefaultLifecycleObserver
import androidx.lifecycle.LifecycleOwner
import androidx.lifecycle.ProcessLifecycleOwner
@@ -14,11 +15,13 @@ import com.bitwarden.authenticatorbridge.IAuthenticatorBridgeService
import com.bitwarden.authenticatorbridge.manager.model.AccountSyncState
import com.bitwarden.authenticatorbridge.manager.model.AuthenticatorBridgeConnectionType
import com.bitwarden.authenticatorbridge.manager.util.toPackageName
import com.bitwarden.authenticatorbridge.model.AddTotpLoginItemData
import com.bitwarden.authenticatorbridge.model.EncryptedSharedAccountData
import com.bitwarden.authenticatorbridge.provider.AuthenticatorBridgeCallbackProvider
import com.bitwarden.authenticatorbridge.provider.StubAuthenticatorBridgeCallbackProvider
import com.bitwarden.authenticatorbridge.provider.SymmetricKeyStorageProvider
import com.bitwarden.authenticatorbridge.util.decrypt
import com.bitwarden.authenticatorbridge.util.encrypt
import com.bitwarden.authenticatorbridge.util.isBuildVersionBelow
import com.bitwarden.authenticatorbridge.util.toFingerprint
import kotlinx.coroutines.flow.MutableStateFlow
@@ -103,6 +106,21 @@ internal class AuthenticatorBridgeManagerImpl(
)
}
override fun startAddTotpLoginItemFlow(totpUri: String): Boolean =
bridgeService
?.safeCall {
// Grab symmetric key data from local storage:
val symmetricKey = symmetricKeyStorageProvider.symmetricKey ?: return@safeCall false
// Encrypt the given URI:
val addTotpData = AddTotpLoginItemData(totpUri).encrypt(symmetricKey).getOrThrow()
return@safeCall this.startAddTotpLoginItemFlow(addTotpData)
}
?.fold(
onFailure = { false },
onSuccess = { true }
)
?: false
private fun bindService() {
if (isBuildVersionBelow(Build.VERSION_CODES.S)) {
mutableSharedAccountsStateFlow.value = AccountSyncState.OsVersionNotSupported
@@ -119,11 +137,17 @@ internal class AuthenticatorBridgeManagerImpl(
)
}
val flags = if (isBuildVersionBelow(Build.VERSION_CODES.UPSIDE_DOWN_CAKE)) {
Context.BIND_AUTO_CREATE
} else {
Context.BIND_AUTO_CREATE or Context.BIND_ALLOW_ACTIVITY_STARTS
}
val isBound = try {
applicationContext.bindService(
intent,
bridgeServiceConnection,
Context.BIND_AUTO_CREATE,
flags,
)
} catch (e: SecurityException) {
unbindService()

View File

@@ -118,7 +118,7 @@ internal fun AddTotpLoginItemData.encrypt(
*
* @param symmetricEncryptionKeyData Symmetric key used for decryption.
*/
internal fun EncryptedAddTotpLoginItemData.decrypt(
fun EncryptedAddTotpLoginItemData.decrypt(
symmetricEncryptionKeyData: SymmetricEncryptionKeyData,
): Result<AddTotpLoginItemData> = runCatching {
val encodedKey = symmetricEncryptionKeyData