@@ -142,10 +142,16 @@ class MainActivity : AppCompatActivity(), CoroutineScope by MainScope() {
142142
143143 app.trackEvent(" Setup" , " action-view" )
144144
145- when (intent.action) {
145+ // RC intents are intents that have passed the RC permission requirement in the manifest.
146+ // Implicit intents with the matching actions will always use the RC activity, this check
147+ // protects against explicit intents targeting MainActivity. RC intents are known to be
148+ // trustworthy, so are allowed to silently activate/deactivate the VPN connection.
149+ val isRCIntent = intent.component?.className == " tech.httptoolkit.android.RemoteControlMainActivity"
150+
151+ when {
146152 // ACTION_VIEW means that somebody had the app installed, and scanned the barcode with
147153 // a separate barcode app anyway (or opened the QR code URL in a browser)
148- Intent .ACTION_VIEW -> {
154+ intent.action == Intent .ACTION_VIEW -> {
149155 if (app.lastProxy != null && isVpnConfigured()) {
150156 Log .i(TAG , " Showing prompt for ACTION_VIEW intent" )
151157
@@ -174,16 +180,22 @@ class MainActivity : AppCompatActivity(), CoroutineScope by MainScope() {
174180 }
175181 }
176182
177- // RPC setup API, used by ADB to enable/disable without prompts.
183+ // RC setup API, used by ADB to enable/disable without prompts.
178184 // Permission required, checked for via activity-alias in the manifest
179- ACTIVATE_INTENT -> {
185+ isRCIntent && intent.action == ACTIVATE_INTENT -> {
180186 launch { connectToVpnFromUrl(intent.data!! ) }
181187 }
182- DEACTIVATE_INTENT -> {
188+ isRCIntent && intent.action == DEACTIVATE_INTENT -> {
183189 disconnect()
184190 }
185191
186- else -> Log .w(TAG , " Unknown intent. Action ${intent.action} , data: ${intent.data} " )
192+ else -> Log .w(TAG , " Unknown intent. Action ${
193+ intent.action
194+ } , data: ${
195+ intent.data
196+ } , ${
197+ if (isRCIntent) " sent as RC intent" else " non-RC"
198+ } " )
187199 }
188200 }
189201
0 commit comments