From f912e00d214cfd306badad3fe8b049be5bad59b5 Mon Sep 17 00:00:00 2001 From: Patrick Honkonen <1883101+SaintPatrck@users.noreply.github.com> Date: Fri, 14 Jun 2024 15:06:45 -0400 Subject: [PATCH] [BWA-10] Sanitize launch intents before processing (#128) --- .../bitwarden/authenticator/MainActivity.kt | 18 ++++-- .../data/platform/util/IntentExtensions.kt | 13 ++++ .../platform/util/IntentExtensionsTest.kt | 64 +++++++++++++++++++ 3 files changed, 90 insertions(+), 5 deletions(-) create mode 100644 app/src/main/kotlin/com/bitwarden/authenticator/data/platform/util/IntentExtensions.kt create mode 100644 app/src/test/java/com/bitwarden/authenticator/data/platform/util/IntentExtensionsTest.kt diff --git a/app/src/main/kotlin/com/bitwarden/authenticator/MainActivity.kt b/app/src/main/kotlin/com/bitwarden/authenticator/MainActivity.kt index 49d1d868b..28ca0d1dc 100644 --- a/app/src/main/kotlin/com/bitwarden/authenticator/MainActivity.kt +++ b/app/src/main/kotlin/com/bitwarden/authenticator/MainActivity.kt @@ -2,7 +2,6 @@ package com.bitwarden.authenticator import android.content.Intent import android.os.Bundle -import android.util.Log import android.view.WindowManager import androidx.activity.compose.setContent import androidx.activity.viewModels @@ -11,6 +10,7 @@ import androidx.compose.runtime.getValue import androidx.core.splashscreen.SplashScreen.Companion.installSplashScreen import androidx.lifecycle.compose.collectAsStateWithLifecycle import androidx.lifecycle.lifecycleScope +import com.bitwarden.authenticator.data.platform.util.isSuspicious import com.bitwarden.authenticator.ui.platform.feature.rootnav.RootNavScreen import com.bitwarden.authenticator.ui.platform.theme.AuthenticatorTheme import dagger.hilt.android.AndroidEntryPoint @@ -23,6 +23,7 @@ class MainActivity : AppCompatActivity() { private val mainViewModel: MainViewModel by viewModels() override fun onCreate(savedInstanceState: Bundle?) { + sanitizeIntent() var shouldShowSplashScreen = true installSplashScreen().setKeepOnScreenCondition { shouldShowSplashScreen } super.onCreate(savedInstanceState) @@ -53,18 +54,26 @@ class MainActivity : AppCompatActivity() { override fun onNewIntent(intent: Intent) { super.onNewIntent(intent) + sanitizeIntent() mainViewModel.trySendAction( MainAction.ReceiveNewIntent(intent = intent) ) } + private fun sanitizeIntent() { + if (intent.isSuspicious) { + intent = Intent( + /* packageContext = */ this, + /* cls = */ MainActivity::class.java, + ) + } + } + private fun observeViewModelEvents() { - Log.d("TAG", "observeViewModelEvents() called") mainViewModel .eventFlow .onEach { event -> - Log.d("TAG", "observeViewModelEvents: onEach $event") - when(event) { + when (event) { is MainEvent.ScreenCaptureSettingChange -> { handleScreenCaptureSettingChange(event) } @@ -74,7 +83,6 @@ class MainActivity : AppCompatActivity() { } private fun handleScreenCaptureSettingChange(event: MainEvent.ScreenCaptureSettingChange) { - Log.d("TAG", "handleScreenCaptureSettingChange() called with: event = $event") if (event.isAllowed) { window.clearFlags(WindowManager.LayoutParams.FLAG_SECURE) } else { diff --git a/app/src/main/kotlin/com/bitwarden/authenticator/data/platform/util/IntentExtensions.kt b/app/src/main/kotlin/com/bitwarden/authenticator/data/platform/util/IntentExtensions.kt new file mode 100644 index 000000000..0423de8af --- /dev/null +++ b/app/src/main/kotlin/com/bitwarden/authenticator/data/platform/util/IntentExtensions.kt @@ -0,0 +1,13 @@ +package com.bitwarden.authenticator.data.platform.util + +import android.content.Intent + +/** + * Returns true if this intent contains unexpected or suspicious data. + */ +val Intent.isSuspicious: Boolean + get() { + val containsSuspiciousExtras = extras?.isEmpty?.not() ?: false + val containsSuspiciousData = data != null + return containsSuspiciousData || containsSuspiciousExtras + } diff --git a/app/src/test/java/com/bitwarden/authenticator/data/platform/util/IntentExtensionsTest.kt b/app/src/test/java/com/bitwarden/authenticator/data/platform/util/IntentExtensionsTest.kt new file mode 100644 index 000000000..a158eb8ff --- /dev/null +++ b/app/src/test/java/com/bitwarden/authenticator/data/platform/util/IntentExtensionsTest.kt @@ -0,0 +1,64 @@ +package com.bitwarden.authenticator.data.platform.util + +import android.content.Intent +import io.mockk.every +import io.mockk.mockk +import org.junit.jupiter.api.Assertions.assertFalse +import org.junit.jupiter.api.Assertions.assertTrue +import org.junit.jupiter.api.Test + +class IntentExtensionsTest { + @Test + fun `isSuspicious should return true when extras are not empty`() { + val intent = mockk { + every { data } returns mockk() + every { extras } returns mockk { + every { isEmpty } returns false + } + } + + assertTrue(intent.isSuspicious) + } + + @Test + fun `isSuspicious should return true when extras are null`() { + val intent = mockk { + every { data } returns mockk() + every { extras } returns null + } + + assertTrue(intent.isSuspicious) + } + + @Test + fun `isSuspicious should return true when data is not null`() { + val intent = mockk { + every { data } returns mockk() + every { extras } returns null + } + + assertTrue(intent.isSuspicious) + } + + @Test + fun `isSuspicious should return false when data and extras are null`() { + val intent = mockk { + every { data } returns null + every { extras } returns null + } + + assertFalse(intent.isSuspicious) + } + + @Test + fun `isSuspicious should return false when data is null and extras are empty`() { + val intent = mockk { + every { data } returns null + every { extras } returns mockk { + every { isEmpty } returns true + } + } + + assertFalse(intent.isSuspicious) + } +}