From 0a9710c73112b4c0a2d6bf478ce2b12c7e914df2 Mon Sep 17 00:00:00 2001 From: Soren Stoutner Date: Sat, 17 Jun 2023 13:21:17 -0700 Subject: [PATCH] Fix a crash when restiarting while the SSL Error Dialog is displayed. https://redmine.stoutner.com/issues/693 --- .../dialogs/SslCertificateErrorDialog.kt | 417 ++++++++++-------- .../views/NestedScrollWebView.kt | 118 ++--- app/src/main/res/values-de/strings.xml | 2 + app/src/main/res/values-es/strings.xml | 2 + app/src/main/res/values-ru/strings.xml | 2 + 5 files changed, 286 insertions(+), 255 deletions(-) diff --git a/app/src/main/java/com/stoutner/privacybrowser/dialogs/SslCertificateErrorDialog.kt b/app/src/main/java/com/stoutner/privacybrowser/dialogs/SslCertificateErrorDialog.kt index aa0ae908..63acae3f 100644 --- a/app/src/main/java/com/stoutner/privacybrowser/dialogs/SslCertificateErrorDialog.kt +++ b/app/src/main/java/com/stoutner/privacybrowser/dialogs/SslCertificateErrorDialog.kt @@ -28,6 +28,7 @@ import android.text.SpannableStringBuilder import android.text.Spanned import android.text.style.ForegroundColorSpan import android.view.WindowManager +import android.webkit.SslErrorHandler import android.widget.TextView import androidx.appcompat.app.AlertDialog @@ -97,217 +98,241 @@ class SslCertificateErrorDialog : DialogFragment() { } } + // Declare the class variables. + private var sslErrorHandler: SslErrorHandler? = null + override fun onCreateDialog(savedInstanceState: Bundle?): Dialog { - // Get the variables from the bundle. - val primaryErrorInt = requireArguments().getInt(PRIMARY_ERROR_INT) - val urlWithErrors = requireArguments().getString(URL_WITH_ERRORS) - val issuedToCName = requireArguments().getString(ISSUED_TO_CNAME) - val issuedToOName = requireArguments().getString(ISSUED_TO_ONAME) - val issuedToUName = requireArguments().getString(ISSUED_TO_UNAME) - val issuedByCName = requireArguments().getString(ISSUED_BY_CNAME) - val issuedByOName = requireArguments().getString(ISSUED_BY_ONAME) - val issuedByUName = requireArguments().getString(ISSUED_BY_UNAME) - val startDate = requireArguments().getString(START_DATE) - val endDate = requireArguments().getString(END_DATE) - val webViewFragmentId = requireArguments().getLong(WEBVIEW_FRAGMENT_ID) - - // Get the current position of this WebView fragment. - val webViewPosition = MainWebViewActivity.webViewStateAdapter!!.getPositionForId(webViewFragmentId) - - // Get the WebView tab fragment. - val webViewTabFragment = MainWebViewActivity.webViewStateAdapter!!.getPageFragment(webViewPosition) - - // Get the fragment view. - val fragmentView = webViewTabFragment.requireView() - - // Get a handle for the current WebView. - val nestedScrollWebView: NestedScrollWebView = fragmentView.findViewById(R.id.nestedscroll_webview) - - // Get a handle for the SSL error handler. - val sslErrorHandler = nestedScrollWebView.sslErrorHandler - - // Use an alert dialog builder to create the alert dialog. - val dialogBuilder = AlertDialog.Builder(requireContext(), R.style.PrivacyBrowserAlertDialog) - - // Set the icon. - dialogBuilder.setIcon(R.drawable.ssl_certificate) - - // Set the title. - dialogBuilder.setTitle(R.string.ssl_certificate_error) - - // Set the view. - dialogBuilder.setView(R.layout.ssl_certificate_error) - - // Set the cancel button listener. - dialogBuilder.setNegativeButton(R.string.cancel) { _: DialogInterface?, _: Int -> - // Check to make sure the SSL error handler is not null. This might happen if multiple dialogs are displayed at once. - if (sslErrorHandler != null) { - // Cancel the request. - sslErrorHandler.cancel() - - // Reset the SSL error handler. - nestedScrollWebView.resetSslErrorHandler() + try { + // Get the variables from the bundle. + val primaryErrorInt = requireArguments().getInt(PRIMARY_ERROR_INT) + val urlWithErrors = requireArguments().getString(URL_WITH_ERRORS) + val issuedToCName = requireArguments().getString(ISSUED_TO_CNAME) + val issuedToOName = requireArguments().getString(ISSUED_TO_ONAME) + val issuedToUName = requireArguments().getString(ISSUED_TO_UNAME) + val issuedByCName = requireArguments().getString(ISSUED_BY_CNAME) + val issuedByOName = requireArguments().getString(ISSUED_BY_ONAME) + val issuedByUName = requireArguments().getString(ISSUED_BY_UNAME) + val startDate = requireArguments().getString(START_DATE) + val endDate = requireArguments().getString(END_DATE) + val webViewFragmentId = requireArguments().getLong(WEBVIEW_FRAGMENT_ID) + + // Get the current position of this WebView fragment. + val webViewPosition = MainWebViewActivity.webViewStateAdapter!!.getPositionForId(webViewFragmentId) + + // Get the WebView tab fragment. + val webViewTabFragment = MainWebViewActivity.webViewStateAdapter!!.getPageFragment(webViewPosition) + + // Get the fragment view. + val fragmentView = webViewTabFragment.requireView() + + // Get a handle for the current WebView. + val nestedScrollWebView: NestedScrollWebView = fragmentView.findViewById(R.id.nestedscroll_webview) + + // Get a handle for the SSL error handler. + sslErrorHandler = nestedScrollWebView.sslErrorHandler + + // Use an alert dialog builder to create the alert dialog. + val dialogBuilder = AlertDialog.Builder(requireContext(), R.style.PrivacyBrowserAlertDialog) + + // Set the icon. + dialogBuilder.setIcon(R.drawable.ssl_certificate) + + // Set the title. + dialogBuilder.setTitle(R.string.ssl_certificate_error) + + // Set the view. + dialogBuilder.setView(R.layout.ssl_certificate_error) + + // Set the cancel button listener. + dialogBuilder.setNegativeButton(R.string.cancel) { _: DialogInterface?, _: Int -> + // Check to make sure the SSL error handler is not null. This might happen if multiple dialogs are displayed at once. + if (sslErrorHandler != null) { + // Cancel the request. + sslErrorHandler!!.cancel() + + // Reset the SSL error handler. + nestedScrollWebView.resetSslErrorHandler() + } } - } - // Set the proceed button listener. - dialogBuilder.setPositiveButton(R.string.proceed) { _: DialogInterface?, _: Int -> - // Check to make sure the SSL error handler is not null. This might happen if multiple dialogs are displayed at once. - if (sslErrorHandler != null) { - // Proceed to the website. - sslErrorHandler.proceed() + // Set the proceed button listener. + dialogBuilder.setPositiveButton(R.string.proceed) { _: DialogInterface?, _: Int -> + // Check to make sure the SSL error handler is not null. This might happen if multiple dialogs are displayed at once. + if (sslErrorHandler != null) { + // Proceed to the website. + sslErrorHandler!!.proceed() - // Reset the SSL error handler. - nestedScrollWebView.resetSslErrorHandler() + // Reset the SSL error handler. + nestedScrollWebView.resetSslErrorHandler() + } } - } - // Create an alert dialog from the builder. - val alertDialog = dialogBuilder.create() + // Create an alert dialog from the builder. + val alertDialog = dialogBuilder.create() - // Get a handle for the shared preferences. - val sharedPreferences = PreferenceManager.getDefaultSharedPreferences(requireContext()) + // Get a handle for the shared preferences. + val sharedPreferences = PreferenceManager.getDefaultSharedPreferences(requireContext()) - // Get the screenshot preference. - val allowScreenshots = sharedPreferences.getBoolean(getString(R.string.allow_screenshots_key), false) - - // Disable screenshots if not allowed. - if (!allowScreenshots) { - // Disable screenshots. - alertDialog.window!!.addFlags(WindowManager.LayoutParams.FLAG_SECURE) - } + // Get the screenshot preference. + val allowScreenshots = sharedPreferences.getBoolean(getString(R.string.allow_screenshots_key), false) - // Get a URI for the URL with errors. - val uriWithErrors = Uri.parse(urlWithErrors) - - // The alert dialog must be shown before the contents can be modified. - alertDialog.show() - - // Get handles for the views. - val primaryErrorTextView = alertDialog.findViewById(R.id.primary_error)!! - val urlTextView = alertDialog.findViewById(R.id.url)!! - val ipAddressesTextView = alertDialog.findViewById(R.id.ip_addresses)!! - val issuedToCNameTextView = alertDialog.findViewById(R.id.issued_to_cname)!! - val issuedToONameTextView = alertDialog.findViewById(R.id.issued_to_oname)!! - val issuedToUNameTextView = alertDialog.findViewById(R.id.issued_to_uname)!! - val issuedByTextView = alertDialog.findViewById(R.id.issued_by_textview)!! - val issuedByCNameTextView = alertDialog.findViewById(R.id.issued_by_cname)!! - val issuedByONameTextView = alertDialog.findViewById(R.id.issued_by_oname)!! - val issuedByUNameTextView = alertDialog.findViewById(R.id.issued_by_uname)!! - val validDatesTextView = alertDialog.findViewById(R.id.valid_dates_textview)!! - val startDateTextView = alertDialog.findViewById(R.id.start_date)!! - val endDateTextView = alertDialog.findViewById(R.id.end_date)!! - - // Define the color spans. - val blueColorSpan = ForegroundColorSpan(requireContext().getColor(R.color.alt_blue_text)) - val redColorSpan = ForegroundColorSpan(requireContext().getColor(R.color.red_text)) - - // Get the IP Addresses for the URI. - GetHostIpAddressesCoroutine.getAddresses(uriWithErrors.host!!, getString(R.string.ip_addresses), blueColorSpan, ipAddressesTextView) - - // Setup the common strings. - val urlLabel = getString(R.string.url_label) - val cNameLabel = getString(R.string.common_name) - val oNameLabel = getString(R.string.organization) - val uNameLabel = getString(R.string.organizational_unit) - val startDateLabel = getString(R.string.start_date) - val endDateLabel = getString(R.string.end_date) - - // Create a spannable string builder for each text view that needs multiple colors of text. - val urlStringBuilder = SpannableStringBuilder(urlLabel + urlWithErrors) - val issuedToCNameStringBuilder = SpannableStringBuilder(cNameLabel + issuedToCName) - val issuedToONameStringBuilder = SpannableStringBuilder(oNameLabel + issuedToOName) - val issuedToUNameStringBuilder = SpannableStringBuilder(uNameLabel + issuedToUName) - val issuedByCNameStringBuilder = SpannableStringBuilder(cNameLabel + issuedByCName) - val issuedByONameStringBuilder = SpannableStringBuilder(oNameLabel + issuedByOName) - val issuedByUNameStringBuilder = SpannableStringBuilder(uNameLabel + issuedByUName) - val startDateStringBuilder = SpannableStringBuilder(startDateLabel + startDate) - val endDateStringBuilder = SpannableStringBuilder(endDateLabel + endDate) - - // Setup the spans to display the certificate information in blue. `SPAN_INCLUSIVE_INCLUSIVE` allows the span to grow in either direction. - urlStringBuilder.setSpan(blueColorSpan, urlLabel.length, urlStringBuilder.length, Spanned.SPAN_INCLUSIVE_INCLUSIVE) - issuedToCNameStringBuilder.setSpan(blueColorSpan, cNameLabel.length, issuedToCNameStringBuilder.length, Spanned.SPAN_INCLUSIVE_INCLUSIVE) - issuedToONameStringBuilder.setSpan(blueColorSpan, oNameLabel.length, issuedToONameStringBuilder.length, Spanned.SPAN_INCLUSIVE_INCLUSIVE) - issuedToUNameStringBuilder.setSpan(blueColorSpan, uNameLabel.length, issuedToUNameStringBuilder.length, Spanned.SPAN_INCLUSIVE_INCLUSIVE) - issuedByCNameStringBuilder.setSpan(blueColorSpan, cNameLabel.length, issuedByCNameStringBuilder.length, Spanned.SPAN_INCLUSIVE_INCLUSIVE) - issuedByONameStringBuilder.setSpan(blueColorSpan, oNameLabel.length, issuedByONameStringBuilder.length, Spanned.SPAN_INCLUSIVE_INCLUSIVE) - issuedByUNameStringBuilder.setSpan(blueColorSpan, uNameLabel.length, issuedByUNameStringBuilder.length, Spanned.SPAN_INCLUSIVE_INCLUSIVE) - startDateStringBuilder.setSpan(blueColorSpan, startDateLabel.length, startDateStringBuilder.length, Spanned.SPAN_INCLUSIVE_INCLUSIVE) - endDateStringBuilder.setSpan(blueColorSpan, endDateLabel.length, endDateStringBuilder.length, Spanned.SPAN_INCLUSIVE_INCLUSIVE) - - // Define the primary error string. - var primaryErrorString = "" - - // Highlight the primary error in red and store it in the primary error string. - when (primaryErrorInt) { - SslError.SSL_IDMISMATCH -> { - // Change the URL span colors to red. - urlStringBuilder.setSpan(redColorSpan, urlLabel.length, urlStringBuilder.length, Spanned.SPAN_INCLUSIVE_INCLUSIVE) - issuedToCNameStringBuilder.setSpan(redColorSpan, cNameLabel.length, issuedToCNameStringBuilder.length, Spanned.SPAN_INCLUSIVE_INCLUSIVE) - - // Store the primary error string. - primaryErrorString = getString(R.string.cn_mismatch) + // Disable screenshots if not allowed. + if (!allowScreenshots) { + // Disable screenshots. + alertDialog.window!!.addFlags(WindowManager.LayoutParams.FLAG_SECURE) } - SslError.SSL_UNTRUSTED -> { - // Change the issued by text view text to red. - issuedByTextView.setTextColor(requireContext().getColor(R.color.red_text)) - - // Change the issued by span color to red. - issuedByCNameStringBuilder.setSpan(redColorSpan, cNameLabel.length, issuedByCNameStringBuilder.length, Spanned.SPAN_INCLUSIVE_INCLUSIVE) - issuedByONameStringBuilder.setSpan(redColorSpan, oNameLabel.length, issuedByONameStringBuilder.length, Spanned.SPAN_INCLUSIVE_INCLUSIVE) - issuedByUNameStringBuilder.setSpan(redColorSpan, uNameLabel.length, issuedByUNameStringBuilder.length, Spanned.SPAN_INCLUSIVE_INCLUSIVE) - - // Store the primary error string. - primaryErrorString = getString(R.string.untrusted) + // Get a URI for the URL with errors. + val uriWithErrors = Uri.parse(urlWithErrors) + + // The alert dialog must be shown before the contents can be modified. + alertDialog.show() + + // Get handles for the views. + val primaryErrorTextView = alertDialog.findViewById(R.id.primary_error)!! + val urlTextView = alertDialog.findViewById(R.id.url)!! + val ipAddressesTextView = alertDialog.findViewById(R.id.ip_addresses)!! + val issuedToCNameTextView = alertDialog.findViewById(R.id.issued_to_cname)!! + val issuedToONameTextView = alertDialog.findViewById(R.id.issued_to_oname)!! + val issuedToUNameTextView = alertDialog.findViewById(R.id.issued_to_uname)!! + val issuedByTextView = alertDialog.findViewById(R.id.issued_by_textview)!! + val issuedByCNameTextView = alertDialog.findViewById(R.id.issued_by_cname)!! + val issuedByONameTextView = alertDialog.findViewById(R.id.issued_by_oname)!! + val issuedByUNameTextView = alertDialog.findViewById(R.id.issued_by_uname)!! + val validDatesTextView = alertDialog.findViewById(R.id.valid_dates_textview)!! + val startDateTextView = alertDialog.findViewById(R.id.start_date)!! + val endDateTextView = alertDialog.findViewById(R.id.end_date)!! + + // Define the color spans. + val blueColorSpan = ForegroundColorSpan(requireContext().getColor(R.color.alt_blue_text)) + val redColorSpan = ForegroundColorSpan(requireContext().getColor(R.color.red_text)) + + // Get the IP Addresses for the URI. + GetHostIpAddressesCoroutine.getAddresses(uriWithErrors.host!!, getString(R.string.ip_addresses), blueColorSpan, ipAddressesTextView) + + // Setup the common strings. + val urlLabel = getString(R.string.url_label) + val cNameLabel = getString(R.string.common_name) + val oNameLabel = getString(R.string.organization) + val uNameLabel = getString(R.string.organizational_unit) + val startDateLabel = getString(R.string.start_date) + val endDateLabel = getString(R.string.end_date) + + // Create a spannable string builder for each text view that needs multiple colors of text. + val urlStringBuilder = SpannableStringBuilder(urlLabel + urlWithErrors) + val issuedToCNameStringBuilder = SpannableStringBuilder(cNameLabel + issuedToCName) + val issuedToONameStringBuilder = SpannableStringBuilder(oNameLabel + issuedToOName) + val issuedToUNameStringBuilder = SpannableStringBuilder(uNameLabel + issuedToUName) + val issuedByCNameStringBuilder = SpannableStringBuilder(cNameLabel + issuedByCName) + val issuedByONameStringBuilder = SpannableStringBuilder(oNameLabel + issuedByOName) + val issuedByUNameStringBuilder = SpannableStringBuilder(uNameLabel + issuedByUName) + val startDateStringBuilder = SpannableStringBuilder(startDateLabel + startDate) + val endDateStringBuilder = SpannableStringBuilder(endDateLabel + endDate) + + // Setup the spans to display the certificate information in blue. `SPAN_INCLUSIVE_INCLUSIVE` allows the span to grow in either direction. + urlStringBuilder.setSpan(blueColorSpan, urlLabel.length, urlStringBuilder.length, Spanned.SPAN_INCLUSIVE_INCLUSIVE) + issuedToCNameStringBuilder.setSpan(blueColorSpan, cNameLabel.length, issuedToCNameStringBuilder.length, Spanned.SPAN_INCLUSIVE_INCLUSIVE) + issuedToONameStringBuilder.setSpan(blueColorSpan, oNameLabel.length, issuedToONameStringBuilder.length, Spanned.SPAN_INCLUSIVE_INCLUSIVE) + issuedToUNameStringBuilder.setSpan(blueColorSpan, uNameLabel.length, issuedToUNameStringBuilder.length, Spanned.SPAN_INCLUSIVE_INCLUSIVE) + issuedByCNameStringBuilder.setSpan(blueColorSpan, cNameLabel.length, issuedByCNameStringBuilder.length, Spanned.SPAN_INCLUSIVE_INCLUSIVE) + issuedByONameStringBuilder.setSpan(blueColorSpan, oNameLabel.length, issuedByONameStringBuilder.length, Spanned.SPAN_INCLUSIVE_INCLUSIVE) + issuedByUNameStringBuilder.setSpan(blueColorSpan, uNameLabel.length, issuedByUNameStringBuilder.length, Spanned.SPAN_INCLUSIVE_INCLUSIVE) + startDateStringBuilder.setSpan(blueColorSpan, startDateLabel.length, startDateStringBuilder.length, Spanned.SPAN_INCLUSIVE_INCLUSIVE) + endDateStringBuilder.setSpan(blueColorSpan, endDateLabel.length, endDateStringBuilder.length, Spanned.SPAN_INCLUSIVE_INCLUSIVE) + + // Define the primary error string. + var primaryErrorString = "" + + // Highlight the primary error in red and store it in the primary error string. + when (primaryErrorInt) { + SslError.SSL_IDMISMATCH -> { + // Change the URL span colors to red. + urlStringBuilder.setSpan(redColorSpan, urlLabel.length, urlStringBuilder.length, Spanned.SPAN_INCLUSIVE_INCLUSIVE) + issuedToCNameStringBuilder.setSpan(redColorSpan, cNameLabel.length, issuedToCNameStringBuilder.length, Spanned.SPAN_INCLUSIVE_INCLUSIVE) + + // Store the primary error string. + primaryErrorString = getString(R.string.cn_mismatch) + } + + SslError.SSL_UNTRUSTED -> { + // Change the issued by text view text to red. + issuedByTextView.setTextColor(requireContext().getColor(R.color.red_text)) + + // Change the issued by span color to red. + issuedByCNameStringBuilder.setSpan(redColorSpan, cNameLabel.length, issuedByCNameStringBuilder.length, Spanned.SPAN_INCLUSIVE_INCLUSIVE) + issuedByONameStringBuilder.setSpan(redColorSpan, oNameLabel.length, issuedByONameStringBuilder.length, Spanned.SPAN_INCLUSIVE_INCLUSIVE) + issuedByUNameStringBuilder.setSpan(redColorSpan, uNameLabel.length, issuedByUNameStringBuilder.length, Spanned.SPAN_INCLUSIVE_INCLUSIVE) + + // Store the primary error string. + primaryErrorString = getString(R.string.untrusted) + } + + SslError.SSL_DATE_INVALID -> { + // Change the valid dates text view text to red. + validDatesTextView.setTextColor(requireContext().getColor(R.color.red_text)) + + // Change the date span colors to red. + startDateStringBuilder.setSpan(redColorSpan, startDateLabel.length, startDateStringBuilder.length, Spanned.SPAN_INCLUSIVE_INCLUSIVE) + endDateStringBuilder.setSpan(redColorSpan, endDateLabel.length, endDateStringBuilder.length, Spanned.SPAN_INCLUSIVE_INCLUSIVE) + + // Store the primary error string. + primaryErrorString = getString(R.string.invalid_date) + } + + SslError.SSL_NOTYETVALID -> { + // Change the start date span color to red. + startDateStringBuilder.setSpan(redColorSpan, startDateLabel.length, startDateStringBuilder.length, Spanned.SPAN_INCLUSIVE_INCLUSIVE) + + // Store the primary error string. + primaryErrorString = getString(R.string.future_certificate) + } + + SslError.SSL_EXPIRED -> { + // Change the end date span color to red. + endDateStringBuilder.setSpan(redColorSpan, endDateLabel.length, endDateStringBuilder.length, Spanned.SPAN_INCLUSIVE_INCLUSIVE) + + // Store the primary error string. + primaryErrorString = getString(R.string.expired_certificate) + } + + SslError.SSL_INVALID -> + // Store the primary error string. + primaryErrorString = getString(R.string.invalid_certificate) } - SslError.SSL_DATE_INVALID -> { - // Change the valid dates text view text to red. - validDatesTextView.setTextColor(requireContext().getColor(R.color.red_text)) - - // Change the date span colors to red. - startDateStringBuilder.setSpan(redColorSpan, startDateLabel.length, startDateStringBuilder.length, Spanned.SPAN_INCLUSIVE_INCLUSIVE) - endDateStringBuilder.setSpan(redColorSpan, endDateLabel.length, endDateStringBuilder.length, Spanned.SPAN_INCLUSIVE_INCLUSIVE) - - // Store the primary error string. - primaryErrorString = getString(R.string.invalid_date) - } - - SslError.SSL_NOTYETVALID -> { - // Change the start date span color to red. - startDateStringBuilder.setSpan(redColorSpan, startDateLabel.length, startDateStringBuilder.length, Spanned.SPAN_INCLUSIVE_INCLUSIVE) - - // Store the primary error string. - primaryErrorString = getString(R.string.future_certificate) - } - - SslError.SSL_EXPIRED -> { - // Change the end date span color to red. - endDateStringBuilder.setSpan(redColorSpan, endDateLabel.length, endDateStringBuilder.length, Spanned.SPAN_INCLUSIVE_INCLUSIVE) - - // Store the primary error string. - primaryErrorString = getString(R.string.expired_certificate) + // Display the strings. + primaryErrorTextView.text = primaryErrorString + urlTextView.text = urlStringBuilder + issuedToCNameTextView.text = issuedToCNameStringBuilder + issuedToONameTextView.text = issuedToONameStringBuilder + issuedToUNameTextView.text = issuedToUNameStringBuilder + issuedByCNameTextView.text = issuedByCNameStringBuilder + issuedByONameTextView.text = issuedByONameStringBuilder + issuedByUNameTextView.text = issuedByUNameStringBuilder + startDateTextView.text = startDateStringBuilder + endDateTextView.text = endDateStringBuilder + + // Return the alert dialog. + return alertDialog + } catch (exception: Exception) { // The app was restarted while the dialog was displayed. + // Dismiss this new instance of the dialog as soon as it is displayed. + dismiss() + + // Use an alert dialog builder to create an empty alert dialog. + val dialogBuilder = AlertDialog.Builder(requireContext(), R.style.PrivacyBrowserAlertDialog) + + // Return the empty alert dialog. + return dialogBuilder.create() } + } - SslError.SSL_INVALID -> - // Store the primary error string. - primaryErrorString = getString(R.string.invalid_certificate) - } + override fun onSaveInstanceState(outState: Bundle) { + // Run the default commands. + super.onSaveInstanceState(outState) - // Display the strings. - primaryErrorTextView.text = primaryErrorString - urlTextView.text = urlStringBuilder - issuedToCNameTextView.text = issuedToCNameStringBuilder - issuedToONameTextView.text = issuedToONameStringBuilder - issuedToUNameTextView.text = issuedToUNameStringBuilder - issuedByCNameTextView.text = issuedByCNameStringBuilder - issuedByONameTextView.text = issuedByONameStringBuilder - issuedByUNameTextView.text = issuedByUNameStringBuilder - startDateTextView.text = startDateStringBuilder - endDateTextView.text = endDateStringBuilder - - // Return the alert dialog. - return alertDialog + // Cancel the request if the SSL error handler is not null. This resets the WebView so it is not waiting on a response to the error handler if it is restarted in the background. + // Otherwise, after restart, the dialog is no longer displayed, but the error handler is still pending and there is no way to cause the dialog to redisplay for that URL in that tab. + if (sslErrorHandler != null) + sslErrorHandler!!.cancel() } } diff --git a/app/src/main/java/com/stoutner/privacybrowser/views/NestedScrollWebView.kt b/app/src/main/java/com/stoutner/privacybrowser/views/NestedScrollWebView.kt index ee1d62fe..518bc20e 100644 --- a/app/src/main/java/com/stoutner/privacybrowser/views/NestedScrollWebView.kt +++ b/app/src/main/java/com/stoutner/privacybrowser/views/NestedScrollWebView.kt @@ -55,35 +55,35 @@ const val ULTRAPRIVACY = 6 const val THIRD_PARTY_REQUESTS = 7 // Define the private class constants. -private const val DOMAIN_SETTINGS_APPLIED = "domain_settings_applied" -private const val DOMAIN_SETTINGS_DATABASE_ID = "domain_settings_database_id" -private const val CURRENT_DOMAIN_NAME = "current_domain_name" -private const val CURRENT_URl = "current_url" -private const val ACCEPT_COOKIES = "accept_cookies" -private const val EASYLIST_ENABLED = "easylist_enabled" -private const val EASYPRIVACY_ENABLED = "easyprivacy_enabled" -private const val FANBOYS_ANNOYANCE_LIST_ENABLED = "fanboys_annoyance_list_enabled" -private const val FANBOYS_SOCIAL_BLOCKING_LIST_ENABLED = "fanboys_social_blocking_list_enabled" -private const val ULTRALIST_ENABLED = "ultralist_enabled" -private const val ULTRAPRIVACY_ENABLED = "ultraprivacy_enabled" -private const val BLOCK_ALL_THIRD_PARTY_REQUESTS = "block_all_third_party_requests" -private const val HAS_PINNED_SSL_CERTIFICATE = "has_pinned_ssl_certificate" -private const val PINNED_SSL_ISSUED_TO_CNAME = "pinned_ssl_issued_to_cname" -private const val PINNED_SSL_ISSUED_TO_ONAME = "pinned_ssl_issued_to_oname" -private const val PINNED_SSL_ISSUED_TO_UNAME = "pinned_ssl_issued_to_uname" -private const val PINNED_SSL_ISSUED_BY_CNAME = "pinned_ssl_issued_by_cname" -private const val PINNED_SSL_ISSUED_BY_ONAME = "pinned_ssl_issued_by_oname" -private const val PINNED_SSL_ISSUED_BY_UNAME = "pinned_ssl_issued_by_uname" -private const val PINNED_SSL_START_DATE = "pinned_ssl_start_date" -private const val PINNED_SSL_END_DATE = "pinned_ssl_end_date" -private const val PINNED_IP_ADDRESSES = "pinned_ip_addresses" -private const val IGNORE_PINNED_DOMAIN_INFORMATION = "ignore_pinned_domain_information" -private const val SWIPE_TO_REFRESH = "swipe_to_refresh" -private const val JAVASCRIPT_ENABLED = "javascript_enabled" -private const val DOM_STORAGE_ENABLED = "dom_storage_enabled" -private const val USER_AGENT = "user_agent" -private const val WIDE_VIEWPORT = "wide_viewport" -private const val FONT_SIZE = "font_size" +private const val ACCEPT_COOKIES = "A" +private const val BLOCK_ALL_THIRD_PARTY_REQUESTS = "B" +private const val CURRENT_DOMAIN_NAME = "C" +private const val CURRENT_URl = "D" +private const val DOM_STORAGE_ENABLED = "E" +private const val DOMAIN_SETTINGS_APPLIED = "F" +private const val DOMAIN_SETTINGS_DATABASE_ID = "G" +private const val EASYLIST_ENABLED = "H" +private const val EASYPRIVACY_ENABLED = "I" +private const val FANBOYS_ANNOYANCE_LIST_ENABLED = "J" +private const val FANBOYS_SOCIAL_BLOCKING_LIST_ENABLED = "K" +private const val FONT_SIZE = "L" +private const val HAS_PINNED_SSL_CERTIFICATE = "M" +private const val IGNORE_PINNED_DOMAIN_INFORMATION = "N" +private const val JAVASCRIPT_ENABLED = "O" +private const val PINNED_IP_ADDRESSES = "P" +private const val PINNED_SSL_END_DATE = "Q" +private const val PINNED_SSL_ISSUED_BY_CNAME = "R" +private const val PINNED_SSL_ISSUED_BY_ONAME = "S" +private const val PINNED_SSL_ISSUED_BY_UNAME = "T" +private const val PINNED_SSL_ISSUED_TO_CNAME = "U" +private const val PINNED_SSL_ISSUED_TO_ONAME = "V" +private const val PINNED_SSL_ISSUED_TO_UNAME = "W" +private const val PINNED_SSL_START_DATE = "X" +private const val SWIPE_TO_REFRESH = "Y" +private const val ULTRALIST_ENABLED = "Z" +private const val ULTRAPRIVACY_ENABLED = "AA" +private const val USER_AGENT = "AB" +private const val WIDE_VIEWPORT = "AC" // NestedScrollWebView extends WebView to handle nested scrolls (scrolling the app bar off the screen). It also stores extra information about the state of the WebView used by Privacy Browser. class NestedScrollWebView @JvmOverloads constructor(context: Context, attributeSet: AttributeSet? = null, defaultStyle: Int = android.R.attr.webViewStyle) : WebView(context, attributeSet, defaultStyle), @@ -395,35 +395,35 @@ class NestedScrollWebView @JvmOverloads constructor(context: Context, attributeS val savedState = Bundle() // Populate the saved state bundle. - savedState.putBoolean(DOMAIN_SETTINGS_APPLIED, domainSettingsApplied) - savedState.putInt(DOMAIN_SETTINGS_DATABASE_ID, domainSettingsDatabaseId) + savedState.putBoolean(ACCEPT_COOKIES, acceptCookies) + savedState.putBoolean(BLOCK_ALL_THIRD_PARTY_REQUESTS, blockAllThirdPartyRequests) savedState.putString(CURRENT_DOMAIN_NAME, currentDomainName) savedState.putString(CURRENT_URl, currentUrl) - savedState.putBoolean(ACCEPT_COOKIES, acceptCookies) + savedState.putBoolean(DOM_STORAGE_ENABLED, this.settings.domStorageEnabled) + savedState.putBoolean(DOMAIN_SETTINGS_APPLIED, domainSettingsApplied) + savedState.putInt(DOMAIN_SETTINGS_DATABASE_ID, domainSettingsDatabaseId) savedState.putBoolean(EASYLIST_ENABLED, easyListEnabled) savedState.putBoolean(EASYPRIVACY_ENABLED, easyPrivacyEnabled) savedState.putBoolean(FANBOYS_ANNOYANCE_LIST_ENABLED, fanboysAnnoyanceListEnabled) savedState.putBoolean(FANBOYS_SOCIAL_BLOCKING_LIST_ENABLED, fanboysSocialBlockingListEnabled) - savedState.putBoolean(ULTRALIST_ENABLED, ultraListEnabled) - savedState.putBoolean(ULTRAPRIVACY_ENABLED, ultraPrivacyEnabled) - savedState.putBoolean(BLOCK_ALL_THIRD_PARTY_REQUESTS, blockAllThirdPartyRequests) + savedState.putInt(FONT_SIZE, this.settings.textZoom) savedState.putBoolean(HAS_PINNED_SSL_CERTIFICATE, hasPinnedSslCertificate) - savedState.putString(PINNED_SSL_ISSUED_TO_CNAME, pinnedSslIssuedToCName) - savedState.putString(PINNED_SSL_ISSUED_TO_ONAME, pinnedSslIssuedToOName) - savedState.putString(PINNED_SSL_ISSUED_TO_UNAME, pinnedSslIssuedToUName) + savedState.putBoolean(IGNORE_PINNED_DOMAIN_INFORMATION, ignorePinnedDomainInformation) + savedState.putBoolean(JAVASCRIPT_ENABLED, this.settings.javaScriptEnabled) + savedState.putString(PINNED_IP_ADDRESSES, pinnedIpAddresses) + savedState.putLong(PINNED_SSL_END_DATE, pinnedSslEndDate.time) savedState.putString(PINNED_SSL_ISSUED_BY_CNAME, pinnedSslIssuedByCName) savedState.putString(PINNED_SSL_ISSUED_BY_ONAME, pinnedSslIssuedByOName) savedState.putString(PINNED_SSL_ISSUED_BY_UNAME, pinnedSslIssuedByUName) + savedState.putString(PINNED_SSL_ISSUED_TO_CNAME, pinnedSslIssuedToCName) + savedState.putString(PINNED_SSL_ISSUED_TO_ONAME, pinnedSslIssuedToOName) + savedState.putString(PINNED_SSL_ISSUED_TO_UNAME, pinnedSslIssuedToUName) savedState.putLong(PINNED_SSL_START_DATE, pinnedSslStartDate.time) - savedState.putLong(PINNED_SSL_END_DATE, pinnedSslEndDate.time) - savedState.putString(PINNED_IP_ADDRESSES, pinnedIpAddresses) - savedState.putBoolean(IGNORE_PINNED_DOMAIN_INFORMATION, ignorePinnedDomainInformation) savedState.putBoolean(SWIPE_TO_REFRESH, swipeToRefresh) - savedState.putBoolean(JAVASCRIPT_ENABLED, this.settings.javaScriptEnabled) - savedState.putBoolean(DOM_STORAGE_ENABLED, this.settings.domStorageEnabled) + savedState.putBoolean(ULTRALIST_ENABLED, ultraListEnabled) + savedState.putBoolean(ULTRAPRIVACY_ENABLED, ultraPrivacyEnabled) savedState.putString(USER_AGENT, this.settings.userAgentString) savedState.putBoolean(WIDE_VIEWPORT, this.settings.useWideViewPort) - savedState.putInt(FONT_SIZE, this.settings.textZoom) // Return the saved state bundle. return savedState @@ -432,35 +432,35 @@ class NestedScrollWebView @JvmOverloads constructor(context: Context, attributeS // Restore the state. fun restoreNestedScrollWebViewState(savedState: Bundle) { // Restore the class variables. - domainSettingsApplied = savedState.getBoolean(DOMAIN_SETTINGS_APPLIED) - domainSettingsDatabaseId = savedState.getInt(DOMAIN_SETTINGS_DATABASE_ID) + acceptCookies = savedState.getBoolean(ACCEPT_COOKIES) + blockAllThirdPartyRequests = savedState.getBoolean(BLOCK_ALL_THIRD_PARTY_REQUESTS) currentDomainName = savedState.getString(CURRENT_DOMAIN_NAME)!! currentUrl = savedState.getString(CURRENT_URl)!! - acceptCookies = savedState.getBoolean(ACCEPT_COOKIES) + this.settings.domStorageEnabled = savedState.getBoolean(DOM_STORAGE_ENABLED) + domainSettingsApplied = savedState.getBoolean(DOMAIN_SETTINGS_APPLIED) + domainSettingsDatabaseId = savedState.getInt(DOMAIN_SETTINGS_DATABASE_ID) easyListEnabled = savedState.getBoolean(EASYLIST_ENABLED) easyPrivacyEnabled = savedState.getBoolean(EASYPRIVACY_ENABLED) fanboysAnnoyanceListEnabled = savedState.getBoolean(FANBOYS_ANNOYANCE_LIST_ENABLED) fanboysSocialBlockingListEnabled = savedState.getBoolean(FANBOYS_SOCIAL_BLOCKING_LIST_ENABLED) - ultraListEnabled = savedState.getBoolean(ULTRALIST_ENABLED) - ultraPrivacyEnabled = savedState.getBoolean(ULTRAPRIVACY_ENABLED) - blockAllThirdPartyRequests = savedState.getBoolean(BLOCK_ALL_THIRD_PARTY_REQUESTS) + this.settings.textZoom = savedState.getInt(FONT_SIZE) hasPinnedSslCertificate = savedState.getBoolean(HAS_PINNED_SSL_CERTIFICATE) - pinnedSslIssuedToCName = savedState.getString(PINNED_SSL_ISSUED_TO_CNAME)!! - pinnedSslIssuedToOName = savedState.getString(PINNED_SSL_ISSUED_TO_ONAME)!! - pinnedSslIssuedToUName = savedState.getString(PINNED_SSL_ISSUED_TO_UNAME)!! + ignorePinnedDomainInformation = savedState.getBoolean(IGNORE_PINNED_DOMAIN_INFORMATION) + this.settings.javaScriptEnabled = savedState.getBoolean(JAVASCRIPT_ENABLED) + pinnedIpAddresses = savedState.getString(PINNED_IP_ADDRESSES)!! + pinnedSslEndDate = Date(savedState.getLong(PINNED_SSL_END_DATE)) pinnedSslIssuedByCName = savedState.getString(PINNED_SSL_ISSUED_BY_CNAME)!! pinnedSslIssuedByOName = savedState.getString(PINNED_SSL_ISSUED_BY_ONAME)!! pinnedSslIssuedByUName = savedState.getString(PINNED_SSL_ISSUED_BY_UNAME)!! + pinnedSslIssuedToCName = savedState.getString(PINNED_SSL_ISSUED_TO_CNAME)!! + pinnedSslIssuedToOName = savedState.getString(PINNED_SSL_ISSUED_TO_ONAME)!! + pinnedSslIssuedToUName = savedState.getString(PINNED_SSL_ISSUED_TO_UNAME)!! pinnedSslStartDate = Date(savedState.getLong(PINNED_SSL_START_DATE)) - pinnedSslEndDate = Date(savedState.getLong(PINNED_SSL_END_DATE)) - pinnedIpAddresses = savedState.getString(PINNED_IP_ADDRESSES)!! - ignorePinnedDomainInformation = savedState.getBoolean(IGNORE_PINNED_DOMAIN_INFORMATION) swipeToRefresh = savedState.getBoolean(SWIPE_TO_REFRESH) - this.settings.javaScriptEnabled = savedState.getBoolean(JAVASCRIPT_ENABLED) - this.settings.domStorageEnabled = savedState.getBoolean(DOM_STORAGE_ENABLED) + ultraListEnabled = savedState.getBoolean(ULTRALIST_ENABLED) + ultraPrivacyEnabled = savedState.getBoolean(ULTRAPRIVACY_ENABLED) this.settings.userAgentString = savedState.getString(USER_AGENT) this.settings.useWideViewPort = savedState.getBoolean(WIDE_VIEWPORT) - this.settings.textZoom = savedState.getInt(FONT_SIZE) } diff --git a/app/src/main/res/values-de/strings.xml b/app/src/main/res/values-de/strings.xml index 16087e37..70e2a785 100644 --- a/app/src/main/res/values-de/strings.xml +++ b/app/src/main/res/values-de/strings.xml @@ -73,6 +73,8 @@ Unverschlüsselte Website Die Kommunikation mit dieser Website erfolgt nicht verschlüsselt. Dies ermöglicht Dritten, Informationen abzuhören, Ihre Bewegungen im Internet zu beobachten und böswillige Inhalte einzuschleusen. + Content-URL + Content-URLs liefern Daten aus anderen auf Ihrem Gerät installierten Apps. SSL-Zertifikat Schließen Domain diff --git a/app/src/main/res/values-es/strings.xml b/app/src/main/res/values-es/strings.xml index fa21f36f..be8b835b 100644 --- a/app/src/main/res/values-es/strings.xml +++ b/app/src/main/res/values-es/strings.xml @@ -69,6 +69,8 @@ Web sin cifrar La comunicación con esta página web no está cifrada. Esto permite a terceras partes interceptar información, rastrear su navegación e inyectar contenido malicioso. + URL de contenido + Las URL de contenido son datos cargados desde otras aplicaciones de tu dispositivo. Certificado SSL Cerrar Dominio diff --git a/app/src/main/res/values-ru/strings.xml b/app/src/main/res/values-ru/strings.xml index 477751d6..a7555247 100644 --- a/app/src/main/res/values-ru/strings.xml +++ b/app/src/main/res/values-ru/strings.xml @@ -66,6 +66,8 @@ Просмотр сертификата SSL Незашифрованный веб-сайт Соединение с этим сайтом не зашифровано. Это позволяет третьим сторонам перехватывать информацию, отслеживать просмотр и внедрять вредоносный контент. + URL контента + URL контента - это данные, загруженные из других приложений на вашем устройстве. Сертификат SSL Закрыть Домен -- 2.43.0