diff --git a/app/build.gradle.kts b/app/build.gradle.kts index 30c64fd..489a5b0 100644 --- a/app/build.gradle.kts +++ b/app/build.gradle.kts @@ -526,7 +526,7 @@ dependencies { implementation("org.jetbrains:annotations-java5:24.0.1") // debugging - debugImplementation("com.squareup.leakcanary:leakcanary-android:2.11") + debugImplementation("com.squareup.leakcanary:leakcanary-android:2.12") // desugaring coreLibraryDesugaring("com.android.tools:desugar_jdk_libs:2.0.3") diff --git a/app/src/main/kotlin/com/fox2code/mmm/androidacy/AndroidacyActivity.kt b/app/src/main/kotlin/com/fox2code/mmm/androidacy/AndroidacyActivity.kt index d22871f..de6efe6 100644 --- a/app/src/main/kotlin/com/fox2code/mmm/androidacy/AndroidacyActivity.kt +++ b/app/src/main/kotlin/com/fox2code/mmm/androidacy/AndroidacyActivity.kt @@ -300,7 +300,7 @@ class AndroidacyActivity : FoxActivity() { } override fun onConsoleMessage(consoleMessage: ConsoleMessage): Boolean { - if (BuildConfig.DEBUG_HTTP) { + return if (BuildConfig.DEBUG) { when (consoleMessage.messageLevel()) { MessageLevel.TIP -> Timber.tag("JSLog").i(consoleMessage.message()) MessageLevel.LOG -> Timber.tag("JSLog").d(consoleMessage.message()) @@ -308,8 +308,10 @@ class AndroidacyActivity : FoxActivity() { MessageLevel.ERROR -> Timber.tag("JSLog").e(consoleMessage.message()) else -> Timber.tag("JSLog").v(consoleMessage.message()) } + true + } else { + false } - return true } override fun onProgressChanged(view: WebView, newProgress: Int) { @@ -323,8 +325,8 @@ class AndroidacyActivity : FoxActivity() { Timber.i("Progress: %d, setting indeterminate to false", newProgress) prgInd.isIndeterminate = false } - prgInd.setProgressCompat(newProgress, true) - if (newProgress == 100 && prgInd.visibility != View.INVISIBLE) { + prgInd.setProgress(newProgress, true) + if (newProgress == 100 && prgInd.visibility != View.GONE) { Timber.i("Progress: %d, hiding progress bar", newProgress) prgInd.isIndeterminate = true prgInd.visibility = View.GONE diff --git a/app/src/main/kotlin/com/fox2code/mmm/utils/io/net/Http.kt b/app/src/main/kotlin/com/fox2code/mmm/utils/io/net/Http.kt index 402b5c5..1bdc66e 100644 --- a/app/src/main/kotlin/com/fox2code/mmm/utils/io/net/Http.kt +++ b/app/src/main/kotlin/com/fox2code/mmm/utils/io/net/Http.kt @@ -73,7 +73,6 @@ enum class Http {; * can help make the app to work later when the current DNS system * isn't functional or available. * - * * Note: DNS Cache is stored in user data. */ private class FallBackDNS(context: Context, parent: Dns, vararg fallbacks: String?) : Dns { @@ -429,8 +428,7 @@ enum class Http {; } private fun followRedirects( - builder: OkHttpClient.Builder, - followRedirects: Boolean + builder: OkHttpClient.Builder, followRedirects: Boolean ): OkHttpClient.Builder { return builder.followRedirects(followRedirects).followSslRedirects(followRedirects) } @@ -464,14 +462,11 @@ enum class Http {; needCaptchaAndroidacyHost = null } + @Suppress("unused") @JvmStatic @SuppressLint("RestrictedApi") @Throws(IOException::class) fun doHttpGet(url: String, allowCache: Boolean): ByteArray { - if (BuildConfig.DEBUG_HTTP) { - // Log, but set all query parameters values to "****" while keeping the keys - Timber.d("doHttpGet: %s", url.replace("=[^&]*".toRegex(), "=****")) - } var response: Response? response = try { (if (allowCache) getHttpClientWithCache() else getHttpClient())!!.newCall( @@ -480,7 +475,16 @@ enum class Http {; ).get().build() ).execute() } catch (e: IOException) { - Timber.e(e, "Failed to fetch %s", url.replace("=[^&]*".toRegex(), "=****")) + Timber.e(e, "Failed to post %s", url) + // detect ssl errors, i.e., cert authority invalid by looking at the message + if (e.message != null && e.message!!.contains("_CERT_")) { + MainActivity.getFoxActivity(MainApplication.INSTANCE!!).runOnUiThread { + // show toast + Toast.makeText( + MainApplication.INSTANCE, R.string.ssl_error, Toast.LENGTH_LONG + ).show() + } + } throw HttpException(e.message, 0) } if (BuildConfig.DEBUG_HTTP) { @@ -550,6 +554,7 @@ enum class Http {; return responseBody?.bytes() ?: ByteArray(0) } + @Suppress("unused") @JvmStatic @Throws(IOException::class) fun doHttpPost(url: String, data: String, allowCache: Boolean): ByteArray { @@ -560,11 +565,26 @@ enum class Http {; private fun doHttpPostRaw(url: String, data: String, allowCache: Boolean): Any { Timber.d("POST %s", url) var response: Response? - response = (if (allowCache) getHttpClientWithCache() else getHttpClient())!!.newCall( - Request.Builder().url(url).post( - JsonRequestBody.from(data) - ).header("Content-Type", "application/json").build() - ).execute() + try { + response = + (if (allowCache) getHttpClientWithCache() else getHttpClient())!!.newCall( + Request.Builder().url(url).post( + JsonRequestBody.from(data) + ).header("Content-Type", "application/json").build() + ).execute() + } catch (e: IOException) { + Timber.e(e, "Failed to post %s", url) + // detect ssl errors, i.e., cert authority invalid by looking at the message + if (e.message != null && e.message!!.contains("_CERT_")) { + MainActivity.getFoxActivity(MainApplication.INSTANCE!!).runOnUiThread { + // show toast + Toast.makeText( + MainApplication.INSTANCE, R.string.ssl_error, Toast.LENGTH_LONG + ).show() + } + } + throw HttpException(e.message, 0) + } if (response.isRedirect) { // follow redirect with same method Timber.d("doHttpPostRaw: following redirect: %s", response.header("Location")) @@ -623,8 +643,23 @@ enum class Http {; @JvmStatic @Throws(IOException::class) fun doHttpGet(url: String, progressListener: ProgressListener): ByteArray { - val response = - getHttpClient()!!.newCall(Request.Builder().url(url).get().build()).execute() + val response: Response + try { + response = + getHttpClient()!!.newCall(Request.Builder().url(url).get().build()).execute() + } catch (e: IOException) { + Timber.e(e, "Failed to post %s", url) + // detect ssl errors, i.e., cert authority invalid by looking at the message + if (e.message != null && e.message!!.contains("_CERT_")) { + MainActivity.getFoxActivity(MainApplication.INSTANCE!!).runOnUiThread { + // show toast + Toast.makeText( + MainApplication.INSTANCE, R.string.ssl_error, Toast.LENGTH_LONG + ).show() + } + } + throw HttpException(e.message, 0) + } if (response.code != 200 && response.code != 204) { Timber.e("Failed to fetch " + url + ", code: " + response.code) checkNeedCaptchaAndroidacy(url, response.code) @@ -733,7 +768,7 @@ enum class Http {; // are we connected to a network with internet capabilities? val networkCapabilities = connectivityManager.getNetworkCapabilities(connectivityManager.activeNetwork) - val systemSaysYes = networkCapabilities != null && networkCapabilities.hasCapability( + val systemSaysYes = networkCapabilities != null && networkCapabilities.hasCapability( NetworkCapabilities.NET_CAPABILITY_INTERNET ) Timber.d("System says we have internet: $systemSaysYes") @@ -757,17 +792,20 @@ enum class Http {; if (!systemSaysYes) return false // check ourselves val hasInternet = try { - val resp = doHttpGet("https://production-api.androidacy.com/ping", false) + val resp = doHttpGet("https://production-api.androidacy.com/cdn-cgi/trace", false) val respString = String(resp) Timber.d("Ping response: $respString") - true + // resp should include that scheme is https and h is production-api.androidacy.com + respString.contains("scheme=https") && respString.contains("h=production-api.androidacy.com") } catch (e: HttpException) { Timber.e(e, "Failed to check internet connection") false } Timber.d("We say we have internet: $hasInternet") lastConnectivityCheck = System.currentTimeMillis() - lastConnectivityResult = systemSaysYes && hasInternet + @Suppress("KotlinConstantConditions") + lastConnectivityResult = + systemSaysYes && hasInternet return lastConnectivityResult } } diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml index 592e8c0..c1a9e81 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -386,4 +386,5 @@ Saved logs successfully Error in opening module notes. Logs may have the reason. Submit feedback + Potential SSL interception detected.