Skip to content
This repository was archived by the owner on Mar 6, 2025. It is now read-only.

Commit f912e00

Browse files
authored
[BWA-10] Sanitize launch intents before processing (#128)
1 parent 7ca1eab commit f912e00

File tree

3 files changed

+90
-5
lines changed

3 files changed

+90
-5
lines changed

app/src/main/kotlin/com/bitwarden/authenticator/MainActivity.kt

Lines changed: 13 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,6 @@ package com.bitwarden.authenticator
22

33
import android.content.Intent
44
import android.os.Bundle
5-
import android.util.Log
65
import android.view.WindowManager
76
import androidx.activity.compose.setContent
87
import androidx.activity.viewModels
@@ -11,6 +10,7 @@ import androidx.compose.runtime.getValue
1110
import androidx.core.splashscreen.SplashScreen.Companion.installSplashScreen
1211
import androidx.lifecycle.compose.collectAsStateWithLifecycle
1312
import androidx.lifecycle.lifecycleScope
13+
import com.bitwarden.authenticator.data.platform.util.isSuspicious
1414
import com.bitwarden.authenticator.ui.platform.feature.rootnav.RootNavScreen
1515
import com.bitwarden.authenticator.ui.platform.theme.AuthenticatorTheme
1616
import dagger.hilt.android.AndroidEntryPoint
@@ -23,6 +23,7 @@ class MainActivity : AppCompatActivity() {
2323
private val mainViewModel: MainViewModel by viewModels()
2424

2525
override fun onCreate(savedInstanceState: Bundle?) {
26+
sanitizeIntent()
2627
var shouldShowSplashScreen = true
2728
installSplashScreen().setKeepOnScreenCondition { shouldShowSplashScreen }
2829
super.onCreate(savedInstanceState)
@@ -53,18 +54,26 @@ class MainActivity : AppCompatActivity() {
5354

5455
override fun onNewIntent(intent: Intent) {
5556
super.onNewIntent(intent)
57+
sanitizeIntent()
5658
mainViewModel.trySendAction(
5759
MainAction.ReceiveNewIntent(intent = intent)
5860
)
5961
}
6062

63+
private fun sanitizeIntent() {
64+
if (intent.isSuspicious) {
65+
intent = Intent(
66+
/* packageContext = */ this,
67+
/* cls = */ MainActivity::class.java,
68+
)
69+
}
70+
}
71+
6172
private fun observeViewModelEvents() {
62-
Log.d("TAG", "observeViewModelEvents() called")
6373
mainViewModel
6474
.eventFlow
6575
.onEach { event ->
66-
Log.d("TAG", "observeViewModelEvents: onEach $event")
67-
when(event) {
76+
when (event) {
6877
is MainEvent.ScreenCaptureSettingChange -> {
6978
handleScreenCaptureSettingChange(event)
7079
}
@@ -74,7 +83,6 @@ class MainActivity : AppCompatActivity() {
7483
}
7584

7685
private fun handleScreenCaptureSettingChange(event: MainEvent.ScreenCaptureSettingChange) {
77-
Log.d("TAG", "handleScreenCaptureSettingChange() called with: event = $event")
7886
if (event.isAllowed) {
7987
window.clearFlags(WindowManager.LayoutParams.FLAG_SECURE)
8088
} else {
Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
package com.bitwarden.authenticator.data.platform.util
2+
3+
import android.content.Intent
4+
5+
/**
6+
* Returns true if this intent contains unexpected or suspicious data.
7+
*/
8+
val Intent.isSuspicious: Boolean
9+
get() {
10+
val containsSuspiciousExtras = extras?.isEmpty?.not() ?: false
11+
val containsSuspiciousData = data != null
12+
return containsSuspiciousData || containsSuspiciousExtras
13+
}
Lines changed: 64 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,64 @@
1+
package com.bitwarden.authenticator.data.platform.util
2+
3+
import android.content.Intent
4+
import io.mockk.every
5+
import io.mockk.mockk
6+
import org.junit.jupiter.api.Assertions.assertFalse
7+
import org.junit.jupiter.api.Assertions.assertTrue
8+
import org.junit.jupiter.api.Test
9+
10+
class IntentExtensionsTest {
11+
@Test
12+
fun `isSuspicious should return true when extras are not empty`() {
13+
val intent = mockk<Intent> {
14+
every { data } returns mockk()
15+
every { extras } returns mockk {
16+
every { isEmpty } returns false
17+
}
18+
}
19+
20+
assertTrue(intent.isSuspicious)
21+
}
22+
23+
@Test
24+
fun `isSuspicious should return true when extras are null`() {
25+
val intent = mockk<Intent> {
26+
every { data } returns mockk()
27+
every { extras } returns null
28+
}
29+
30+
assertTrue(intent.isSuspicious)
31+
}
32+
33+
@Test
34+
fun `isSuspicious should return true when data is not null`() {
35+
val intent = mockk<Intent> {
36+
every { data } returns mockk()
37+
every { extras } returns null
38+
}
39+
40+
assertTrue(intent.isSuspicious)
41+
}
42+
43+
@Test
44+
fun `isSuspicious should return false when data and extras are null`() {
45+
val intent = mockk<Intent> {
46+
every { data } returns null
47+
every { extras } returns null
48+
}
49+
50+
assertFalse(intent.isSuspicious)
51+
}
52+
53+
@Test
54+
fun `isSuspicious should return false when data is null and extras are empty`() {
55+
val intent = mockk<Intent> {
56+
every { data } returns null
57+
every { extras } returns mockk {
58+
every { isEmpty } returns true
59+
}
60+
}
61+
62+
assertFalse(intent.isSuspicious)
63+
}
64+
}

0 commit comments

Comments
 (0)