diff --git a/app/src/main/kotlin/org/koitharu/kotatsu/core/exceptions/resolve/ExceptionResolver.kt b/app/src/main/kotlin/org/koitharu/kotatsu/core/exceptions/resolve/ExceptionResolver.kt index 3f605c9a9..62d5f5a2d 100644 --- a/app/src/main/kotlin/org/koitharu/kotatsu/core/exceptions/resolve/ExceptionResolver.kt +++ b/app/src/main/kotlin/org/koitharu/kotatsu/core/exceptions/resolve/ExceptionResolver.kt @@ -1,36 +1,48 @@ package org.koitharu.kotatsu.core.exceptions.resolve +import android.content.Context +import android.widget.Toast import androidx.activity.result.ActivityResultCallback import androidx.activity.result.ActivityResultLauncher import androidx.annotation.StringRes -import androidx.collection.ArrayMap +import androidx.collection.MutableScatterMap import androidx.fragment.app.Fragment import androidx.fragment.app.FragmentActivity +import com.google.android.material.dialog.MaterialAlertDialogBuilder +import dagger.hilt.android.EntryPointAccessors import org.koitharu.kotatsu.R import org.koitharu.kotatsu.alternatives.ui.AlternativesActivity import org.koitharu.kotatsu.browser.BrowserActivity import org.koitharu.kotatsu.browser.cloudflare.CloudFlareActivity import org.koitharu.kotatsu.core.exceptions.CloudFlareProtectedException import org.koitharu.kotatsu.core.exceptions.UnsupportedSourceException +import org.koitharu.kotatsu.core.prefs.AppSettings +import org.koitharu.kotatsu.core.ui.BaseActivity.BaseActivityEntryPoint import org.koitharu.kotatsu.core.ui.dialog.ErrorDetailsDialog import org.koitharu.kotatsu.core.util.TaggedActivityResult +import org.koitharu.kotatsu.core.util.ext.findActivity import org.koitharu.kotatsu.parsers.exception.AuthRequiredException import org.koitharu.kotatsu.parsers.exception.NotFoundException import org.koitharu.kotatsu.parsers.model.Manga import org.koitharu.kotatsu.parsers.model.MangaSource import org.koitharu.kotatsu.settings.sources.auth.SourceAuthActivity +import java.security.cert.CertPathValidatorException +import javax.net.ssl.SSLException import kotlin.coroutines.Continuation import kotlin.coroutines.resume import kotlin.coroutines.suspendCoroutine class ExceptionResolver : ActivityResultCallback { - private val continuations = ArrayMap>(1) + private val continuations = MutableScatterMap>(1) private val activity: FragmentActivity? private val fragment: Fragment? private val sourceAuthContract: ActivityResultLauncher private val cloudflareContract: ActivityResultLauncher + val context: Context? + get() = activity ?: fragment?.context + constructor(activity: FragmentActivity) { this.activity = activity fragment = null @@ -56,6 +68,12 @@ class ExceptionResolver : ActivityResultCallback { suspend fun resolve(e: Throwable): Boolean = when (e) { is CloudFlareProtectedException -> resolveCF(e) is AuthRequiredException -> resolveAuthException(e.source) + is SSLException, + is CertPathValidatorException -> { + showSslErrorDialog() + false + } + is NotFoundException -> { openInBrowser(e.url) false @@ -80,13 +98,37 @@ class ExceptionResolver : ActivityResultCallback { } private fun openInBrowser(url: String) { - val context = activity ?: fragment?.activity ?: return - context.startActivity(BrowserActivity.newIntent(context, url, null, null)) + context?.run { + startActivity(BrowserActivity.newIntent(this, url, null, null)) + } } private fun openAlternatives(manga: Manga) { - val context = activity ?: fragment?.activity ?: return - context.startActivity(AlternativesActivity.newIntent(context, manga)) + context?.run { + startActivity(AlternativesActivity.newIntent(this, manga)) + } + } + + private fun showSslErrorDialog() { + val ctx = context ?: return + val settings = getAppSettings(ctx) + if (settings.isSSLBypassEnabled) { + Toast.makeText(ctx, R.string.operation_not_supported, Toast.LENGTH_SHORT).show() + return + } + MaterialAlertDialogBuilder(ctx) + .setTitle(R.string.ignore_ssl_errors) + .setMessage(R.string.ignore_ssl_errors_summary) + .setPositiveButton(R.string.apply) { _, _ -> + settings.isSSLBypassEnabled = true + Toast.makeText(ctx, R.string.settings_apply_restart_required, Toast.LENGTH_SHORT).show() + ctx.findActivity()?.finishAffinity() + }.setNegativeButton(android.R.string.cancel, null) + .show() + } + + private fun getAppSettings(context: Context): AppSettings { + return EntryPointAccessors.fromApplication(context).settings } private fun getFragmentManager() = checkNotNull(fragment?.childFragmentManager ?: activity?.supportFragmentManager) @@ -99,6 +141,9 @@ class ExceptionResolver : ActivityResultCallback { is AuthRequiredException -> R.string.sign_in is NotFoundException -> if (e.url.isNotEmpty()) R.string.open_in_browser else 0 is UnsupportedSourceException -> if (e.manga != null) R.string.alternatives else 0 + is SSLException, + is CertPathValidatorException -> R.string.fix + else -> 0 } diff --git a/app/src/main/kotlin/org/koitharu/kotatsu/core/prefs/AppSettings.kt b/app/src/main/kotlin/org/koitharu/kotatsu/core/prefs/AppSettings.kt index 94cda77b9..9a1c128e3 100644 --- a/app/src/main/kotlin/org/koitharu/kotatsu/core/prefs/AppSettings.kt +++ b/app/src/main/kotlin/org/koitharu/kotatsu/core/prefs/AppSettings.kt @@ -386,8 +386,9 @@ class AppSettings @Inject constructor(@ApplicationContext context: Context) { val dnsOverHttps: DoHProvider get() = prefs.getEnumValue(KEY_DOH, DoHProvider.NONE) - val isSSLBypassEnabled: Boolean + var isSSLBypassEnabled: Boolean get() = prefs.getBoolean(KEY_SSL_BYPASS, false) + set(value) = prefs.edit { putBoolean(KEY_SSL_BYPASS, value) } val proxyType: Proxy.Type get() { diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml index e4a333a11..c072f1951 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -644,4 +644,6 @@ Disable Sources disabled Disable connectivity check + You can disable SSL certificates verification in case you face an SSL-related issues when accessing network resources. This may affect your security. Application restarting is required after changing this setting. + Skip the connectivity check in case you have issues with it (e.g. going offline mode even though the network is connected) diff --git a/app/src/main/res/xml/pref_network.xml b/app/src/main/res/xml/pref_network.xml index dd42ab93c..d32293566 100644 --- a/app/src/main/res/xml/pref_network.xml +++ b/app/src/main/res/xml/pref_network.xml @@ -47,10 +47,12 @@