Skip to content
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

[BWA-10] Sanitize launch intents before processing #128

Merged
merged 2 commits into from
Jun 14, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
18 changes: 13 additions & 5 deletions app/src/main/kotlin/com/bitwarden/authenticator/MainActivity.kt
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand All @@ -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
Expand All @@ -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)
Expand Down Expand Up @@ -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)
}
Expand All @@ -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 {
Expand Down
Original file line number Diff line number Diff line change
@@ -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
}
Original file line number Diff line number Diff line change
@@ -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<Intent> {
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<Intent> {
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<Intent> {
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<Intent> {
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<Intent> {
every { data } returns null
every { extras } returns mockk {
every { isEmpty } returns true
}
}

assertFalse(intent.isSuspicious)
}
}
Loading