@@ -59,6 +59,9 @@ private fun getCertificateFingerprint(cert: X509Certificate): String {
5959 return Base64 .encodeToString(fingerprint, Base64 .NO_WRAP )
6060}
6161
62+ private val ACTIVATE_INTENT = " tech.httptoolkit.android.ACTIVATE"
63+ private val DEACTIVATE_INTENT = " tech.httptoolkit.android.DEACTIVATE"
64+
6265class MainActivity : AppCompatActivity (), CoroutineScope by MainScope() {
6366
6467 private val TAG = MainActivity ::class .simpleName
@@ -137,38 +140,50 @@ class MainActivity : AppCompatActivity(), CoroutineScope by MainScope() {
137140 override fun onNewIntent (intent : Intent ) {
138141 super .onNewIntent(intent)
139142
140- if (intent.action != Intent .ACTION_VIEW ) {
141- Log .w(TAG , " Unknown intent. Action ${intent.action} , data: ${intent.data} " )
142- return
143- }
144-
145143 app.trackEvent(" Setup" , " action-view" )
146144
147- if (app.lastProxy != null && isVpnConfigured()) {
148- Log .i(TAG , " Showing prompt for ACTION_VIEW intent" )
149-
150- // If we were started from an intent (e.g. another barcode scanner/link), and we
151- // had a proxy before (so no prompts required) then confirm before starting the VPN.
152- // Without this any QR code you scan could instantly MitM you.
153- MaterialAlertDialogBuilder (this )
154- .setTitle(" Enable Interception" )
155- .setIcon(R .drawable.ic_exclamation_triangle)
156- .setMessage(
157- " Do you want to share all this device's HTTP traffic with HTTP Toolkit?" +
158- " \n\n " +
159- " Only accept this if you trust the source."
160- )
161- .setPositiveButton(" Enable" ) { _, _ ->
162- Log .i(TAG , " Prompt confirmed" )
145+ when (intent.action) {
146+ // ACTION_VIEW means that somebody had the app installed, and scanned the barcode with
147+ // a separate barcode app anyway (or opened the QR code URL in a browser)
148+ Intent .ACTION_VIEW -> {
149+ if (app.lastProxy != null && isVpnConfigured()) {
150+ Log .i(TAG , " Showing prompt for ACTION_VIEW intent" )
151+
152+ // If we were started from an intent (e.g. another barcode scanner/link), and we
153+ // had a proxy before (so no prompts required) then confirm before starting the VPN.
154+ // Without this any QR code you scan could instantly MitM you.
155+ MaterialAlertDialogBuilder (this )
156+ .setTitle(" Enable Interception" )
157+ .setIcon(R .drawable.ic_exclamation_triangle)
158+ .setMessage(
159+ " Do you want to share all this device's HTTP traffic with HTTP Toolkit?" +
160+ " \n\n " +
161+ " Only accept this if you trust the source."
162+ )
163+ .setPositiveButton(" Enable" ) { _, _ ->
164+ Log .i(TAG , " Prompt confirmed" )
165+ launch { connectToVpnFromUrl(intent.data!! ) }
166+ }
167+ .setNegativeButton(" Cancel" ) { _, _ ->
168+ Log .i(TAG , " Prompt cancelled" )
169+ }
170+ .show()
171+ } else {
172+ Log .i(TAG , " Launching from ACTION_VIEW intent" )
163173 launch { connectToVpnFromUrl(intent.data!! ) }
164174 }
165- .setNegativeButton(" Cancel" ) { _, _ ->
166- Log .i(TAG , " Prompt cancelled" )
167- }
168- .show()
169- } else {
170- Log .i(TAG , " Launching from ACTION_VIEW intent" )
171- launch { connectToVpnFromUrl(intent.data!! ) }
175+ }
176+
177+ // RPC setup API, used by ADB to enable/disable without prompts.
178+ // Permission required, checked for via activity-alias in the manifest
179+ ACTIVATE_INTENT -> {
180+ launch { connectToVpnFromUrl(intent.data!! ) }
181+ }
182+ DEACTIVATE_INTENT -> {
183+ disconnect()
184+ }
185+
186+ else -> Log .w(TAG , " Unknown intent. Action ${intent.action} , data: ${intent.data} " )
172187 }
173188 }
174189
0 commit comments