+ // Initialize the third party request tracker.
+ boolean isThirdPartyRequest = false;
+
+ // Initialize the current domain string.
+ String currentDomain = "";
+
+ // Nobody is happy when comparing null strings.
+ if (!(formattedUrlString == null) && !(url == null)) {
+ // Get the domain strings to URIs.
+ Uri currentDomainUri = Uri.parse(formattedUrlString);
+ Uri requestDomainUri = Uri.parse(url);
+
+ // Get the domain host names.
+ String currentBaseDomain = currentDomainUri.getHost();
+ String requestBaseDomain = requestDomainUri.getHost();
+
+ // Update the current domain variable.
+ currentDomain = currentBaseDomain;
+
+ // Only compare the current base domain and the request base domain if neither is null.
+ if (!(currentBaseDomain == null) && !(requestBaseDomain == null)) {
+ // Determine the current base domain.
+ while (currentBaseDomain.indexOf(".", currentBaseDomain.indexOf(".") + 1) > 0) { // There is at least one subdomain.
+ // Remove the first subdomain.
+ currentBaseDomain = currentBaseDomain.substring(currentBaseDomain.indexOf(".") + 1);
+ }
+
+ // Determine the request base domain.
+ while (requestBaseDomain.indexOf(".", requestBaseDomain.indexOf(".") + 1) > 0) { // There is at least one subdomain.
+ // Remove the first subdomain.
+ requestBaseDomain = requestBaseDomain.substring(requestBaseDomain.indexOf(".") + 1);
+ }
+
+ // Update the third party request tracker.
+ isThirdPartyRequest = !currentBaseDomain.equals(requestBaseDomain);
+ }
+ }
+
+ // Get the current WebView page position.
+ int webViewPagePosition = webViewPagerAdapter.getPositionForId(nestedScrollWebView.getWebViewFragmentId());
+
+ // Determine if the WebView is currently displayed.
+ boolean webViewDisplayed = (webViewPagePosition == tabLayout.getSelectedTabPosition());
+
+ // Block third-party requests if enabled.
+ if (isThirdPartyRequest && nestedScrollWebView.isBlocklistEnabled(NestedScrollWebView.THIRD_PARTY_REQUESTS)) {
+ // Add the result to the resource requests.
+ nestedScrollWebView.addResourceRequest(new String[]{BlockListHelper.REQUEST_THIRD_PARTY, url});
+
+ // Increment the blocked requests counters.
+ nestedScrollWebView.incrementRequestsCount(NestedScrollWebView.BLOCKED_REQUESTS);
+ nestedScrollWebView.incrementRequestsCount(NestedScrollWebView.THIRD_PARTY_REQUESTS);
+
+ // Update the titles of the blocklist menu items if the WebView is currently displayed.
+ if (webViewDisplayed) {
+ // Updating the UI must be run from the UI thread.
+ activity.runOnUiThread(() -> {
+ // Update the menu item titles.
+ navigationRequestsMenuItem.setTitle(getString(R.string.requests) + " - " + nestedScrollWebView.getRequestsCount(NestedScrollWebView.BLOCKED_REQUESTS));
+ blocklistsMenuItem.setTitle(getString(R.string.blocklists) + " - " + nestedScrollWebView.getRequestsCount(NestedScrollWebView.BLOCKED_REQUESTS));
+ blockAllThirdPartyRequestsMenuItem.setTitle(nestedScrollWebView.getRequestsCount(NestedScrollWebView.THIRD_PARTY_REQUESTS) + " - " +
+ getString(R.string.block_all_third_party_requests));
+ });
+ }
+
+ // Return an empty web resource response.
+ return emptyWebResourceResponse;
+ }
+
+ // Check UltraPrivacy if it is enabled.
+ if (nestedScrollWebView.isBlocklistEnabled(NestedScrollWebView.ULTRA_PRIVACY)) {
+ // Check the URL against UltraPrivacy.
+ String[] ultraPrivacyResults = blockListHelper.checkBlocklist(currentDomain, url, isThirdPartyRequest, ultraPrivacy);
+
+ // Process the UltraPrivacy results.
+ if (ultraPrivacyResults[0].equals(BlockListHelper.REQUEST_BLOCKED)) { // The resource request matched UltraPrivacy's blacklist.
+ // Add the result to the resource requests.
+ nestedScrollWebView.addResourceRequest(new String[] {ultraPrivacyResults[0], ultraPrivacyResults[1], ultraPrivacyResults[2], ultraPrivacyResults[3], ultraPrivacyResults[4],
+ ultraPrivacyResults[5]});
+
+ // Increment the blocked requests counters.
+ nestedScrollWebView.incrementRequestsCount(NestedScrollWebView.BLOCKED_REQUESTS);
+ nestedScrollWebView.incrementRequestsCount(NestedScrollWebView.ULTRA_PRIVACY);
+
+ // Update the titles of the blocklist menu items if the WebView is currently displayed.
+ if (webViewDisplayed) {
+ // Updating the UI must be run from the UI thread.
+ activity.runOnUiThread(() -> {
+ // Update the menu item titles.
+ navigationRequestsMenuItem.setTitle(getString(R.string.requests) + " - " + nestedScrollWebView.getRequestsCount(NestedScrollWebView.BLOCKED_REQUESTS));
+ blocklistsMenuItem.setTitle(getString(R.string.blocklists) + " - " + nestedScrollWebView.getRequestsCount(NestedScrollWebView.BLOCKED_REQUESTS));
+ ultraPrivacyMenuItem.setTitle(nestedScrollWebView.getRequestsCount(NestedScrollWebView.ULTRA_PRIVACY) + " - " + getString(R.string.ultraprivacy));
+ });
+ }
+
+ // The resource request was blocked. Return an empty web resource response.
+ return emptyWebResourceResponse;
+ } else if (ultraPrivacyResults[0].equals(BlockListHelper.REQUEST_ALLOWED)) { // The resource request matched UltraPrivacy's whitelist.
+ // Add a whitelist entry to the resource requests array.
+ nestedScrollWebView.addResourceRequest(new String[] {ultraPrivacyResults[0], ultraPrivacyResults[1], ultraPrivacyResults[2], ultraPrivacyResults[3], ultraPrivacyResults[4],
+ ultraPrivacyResults[5]});
+
+ // The resource request has been allowed by UltraPrivacy. `return null` loads the requested resource.
+ return null;
+ }
+ }
+
+ // Check EasyList if it is enabled.
+ if (nestedScrollWebView.isBlocklistEnabled(NestedScrollWebView.EASY_LIST)) {
+ // Check the URL against EasyList.
+ String[] easyListResults = blockListHelper.checkBlocklist(currentDomain, url, isThirdPartyRequest, easyList);
+
+ // Process the EasyList results.
+ if (easyListResults[0].equals(BlockListHelper.REQUEST_BLOCKED)) { // The resource request matched EasyList's blacklist.
+ // Add the result to the resource requests.
+ nestedScrollWebView.addResourceRequest(new String[] {easyListResults[0], easyListResults[1], easyListResults[2], easyListResults[3], easyListResults[4], easyListResults[5]});
+
+ // Increment the blocked requests counters.
+ nestedScrollWebView.incrementRequestsCount(NestedScrollWebView.BLOCKED_REQUESTS);
+ nestedScrollWebView.incrementRequestsCount(NestedScrollWebView.EASY_LIST);
+
+ // Update the titles of the blocklist menu items if the WebView is currently displayed.
+ if (webViewDisplayed) {
+ // Updating the UI must be run from the UI thread.
+ activity.runOnUiThread(() -> {
+ // Update the menu item titles.
+ navigationRequestsMenuItem.setTitle(getString(R.string.requests) + " - " + nestedScrollWebView.getRequestsCount(NestedScrollWebView.BLOCKED_REQUESTS));
+ blocklistsMenuItem.setTitle(getString(R.string.blocklists) + " - " + nestedScrollWebView.getRequestsCount(NestedScrollWebView.BLOCKED_REQUESTS));
+ easyListMenuItem.setTitle(nestedScrollWebView.getRequestsCount(NestedScrollWebView.EASY_LIST) + " - " + getString(R.string.easylist));
+ });
+ }
+
+ // The resource request was blocked. Return an empty web resource response.
+ return emptyWebResourceResponse;
+ } else if (easyListResults[0].equals(BlockListHelper.REQUEST_ALLOWED)) { // The resource request matched EasyList's whitelist.
+ // Update the whitelist result string array tracker.
+ whitelistResultStringArray = new String[] {easyListResults[0], easyListResults[1], easyListResults[2], easyListResults[3], easyListResults[4], easyListResults[5]};
+ }
+ }
+
+ // Check EasyPrivacy if it is enabled.
+ if (nestedScrollWebView.isBlocklistEnabled(NestedScrollWebView.EASY_PRIVACY)) {
+ // Check the URL against EasyPrivacy.
+ String[] easyPrivacyResults = blockListHelper.checkBlocklist(currentDomain, url, isThirdPartyRequest, easyPrivacy);
+
+ // Process the EasyPrivacy results.
+ if (easyPrivacyResults[0].equals(BlockListHelper.REQUEST_BLOCKED)) { // The resource request matched EasyPrivacy's blacklist.
+ // Add the result to the resource requests.
+ nestedScrollWebView.addResourceRequest(new String[] {easyPrivacyResults[0], easyPrivacyResults[1], easyPrivacyResults[2], easyPrivacyResults[3], easyPrivacyResults[4],
+ easyPrivacyResults[5]});
+
+ // Increment the blocked requests counters.
+ nestedScrollWebView.incrementRequestsCount(NestedScrollWebView.BLOCKED_REQUESTS);
+ nestedScrollWebView.incrementRequestsCount(NestedScrollWebView.EASY_PRIVACY);
+
+ // Update the titles of the blocklist menu items if the WebView is currently displayed.
+ if (webViewDisplayed) {
+ // Updating the UI must be run from the UI thread.
+ activity.runOnUiThread(() -> {
+ // Update the menu item titles.
+ navigationRequestsMenuItem.setTitle(getString(R.string.requests) + " - " + nestedScrollWebView.getRequestsCount(NestedScrollWebView.BLOCKED_REQUESTS));
+ blocklistsMenuItem.setTitle(getString(R.string.blocklists) + " - " + nestedScrollWebView.getRequestsCount(NestedScrollWebView.BLOCKED_REQUESTS));
+ easyPrivacyMenuItem.setTitle(nestedScrollWebView.getRequestsCount(NestedScrollWebView.EASY_PRIVACY) + " - " + getString(R.string.easyprivacy));
+ });
+ }
+
+ // The resource request was blocked. Return an empty web resource response.
+ return emptyWebResourceResponse;
+ } else if (easyPrivacyResults[0].equals(BlockListHelper.REQUEST_ALLOWED)) { // The resource request matched EasyPrivacy's whitelist.
+ // Update the whitelist result string array tracker.
+ whitelistResultStringArray = new String[] {easyPrivacyResults[0], easyPrivacyResults[1], easyPrivacyResults[2], easyPrivacyResults[3], easyPrivacyResults[4], easyPrivacyResults[5]};
+ }
+ }
+
+ // Check Fanboy’s Annoyance List if it is enabled.
+ if (nestedScrollWebView.isBlocklistEnabled(NestedScrollWebView.FANBOYS_ANNOYANCE_LIST)) {
+ // Check the URL against Fanboy's Annoyance List.
+ String[] fanboysAnnoyanceListResults = blockListHelper.checkBlocklist(currentDomain, url, isThirdPartyRequest, fanboysAnnoyanceList);
+
+ // Process the Fanboy's Annoyance List results.
+ if (fanboysAnnoyanceListResults[0].equals(BlockListHelper.REQUEST_BLOCKED)) { // The resource request matched Fanboy's Annoyance List's blacklist.
+ // Add the result to the resource requests.
+ nestedScrollWebView.addResourceRequest(new String[] {fanboysAnnoyanceListResults[0], fanboysAnnoyanceListResults[1], fanboysAnnoyanceListResults[2], fanboysAnnoyanceListResults[3],
+ fanboysAnnoyanceListResults[4], fanboysAnnoyanceListResults[5]});
+
+ // Increment the blocked requests counters.
+ nestedScrollWebView.incrementRequestsCount(NestedScrollWebView.BLOCKED_REQUESTS);
+ nestedScrollWebView.incrementRequestsCount(NestedScrollWebView.FANBOYS_ANNOYANCE_LIST);
+
+ // Update the titles of the blocklist menu items if the WebView is currently displayed.
+ if (webViewDisplayed) {
+ // Updating the UI must be run from the UI thread.
+ activity.runOnUiThread(() -> {
+ // Update the menu item titles.
+ navigationRequestsMenuItem.setTitle(getString(R.string.requests) + " - " + nestedScrollWebView.getRequestsCount(NestedScrollWebView.BLOCKED_REQUESTS));
+ blocklistsMenuItem.setTitle(getString(R.string.blocklists) + " - " + nestedScrollWebView.getRequestsCount(NestedScrollWebView.BLOCKED_REQUESTS));
+ fanboysAnnoyanceListMenuItem.setTitle(nestedScrollWebView.getRequestsCount(NestedScrollWebView.FANBOYS_ANNOYANCE_LIST) + " - " +
+ getString(R.string.fanboys_annoyance_list));
+ });
+ }
+
+ // The resource request was blocked. Return an empty web resource response.
+ return emptyWebResourceResponse;
+ } else if (fanboysAnnoyanceListResults[0].equals(BlockListHelper.REQUEST_ALLOWED)){ // The resource request matched Fanboy's Annoyance List's whitelist.
+ // Update the whitelist result string array tracker.
+ whitelistResultStringArray = new String[] {fanboysAnnoyanceListResults[0], fanboysAnnoyanceListResults[1], fanboysAnnoyanceListResults[2], fanboysAnnoyanceListResults[3],
+ fanboysAnnoyanceListResults[4], fanboysAnnoyanceListResults[5]};
+ }
+ } else if (nestedScrollWebView.isBlocklistEnabled(NestedScrollWebView.FANBOYS_SOCIAL_BLOCKING_LIST)) { // Only check Fanboy’s Social Blocking List if Fanboy’s Annoyance List is disabled.
+ // Check the URL against Fanboy's Annoyance List.
+ String[] fanboysSocialListResults = blockListHelper.checkBlocklist(currentDomain, url, isThirdPartyRequest, fanboysSocialList);
+
+ // Process the Fanboy's Social Blocking List results.
+ if (fanboysSocialListResults[0].equals(BlockListHelper.REQUEST_BLOCKED)) { // The resource request matched Fanboy's Social Blocking List's blacklist.
+ // Add the result to the resource requests.
+ nestedScrollWebView.addResourceRequest(new String[] {fanboysSocialListResults[0], fanboysSocialListResults[1], fanboysSocialListResults[2], fanboysSocialListResults[3],
+ fanboysSocialListResults[4], fanboysSocialListResults[5]});
+
+ // Increment the blocked requests counters.
+ nestedScrollWebView.incrementRequestsCount(NestedScrollWebView.BLOCKED_REQUESTS);
+ nestedScrollWebView.incrementRequestsCount(NestedScrollWebView.FANBOYS_SOCIAL_BLOCKING_LIST);
+
+ // Update the titles of the blocklist menu items if the WebView is currently displayed.
+ if (webViewDisplayed) {
+ // Updating the UI must be run from the UI thread.
+ activity.runOnUiThread(() -> {
+ // Update the menu item titles.
+ navigationRequestsMenuItem.setTitle(getString(R.string.requests) + " - " + nestedScrollWebView.getRequestsCount(NestedScrollWebView.BLOCKED_REQUESTS));
+ blocklistsMenuItem.setTitle(getString(R.string.blocklists) + " - " + nestedScrollWebView.getRequestsCount(NestedScrollWebView.BLOCKED_REQUESTS));
+ fanboysSocialBlockingListMenuItem.setTitle(nestedScrollWebView.getRequestsCount(NestedScrollWebView.FANBOYS_SOCIAL_BLOCKING_LIST) + " - " +
+ getString(R.string.fanboys_social_blocking_list));
+ });
+ }
+
+ // The resource request was blocked. Return an empty web resource response.
+ return emptyWebResourceResponse;
+ } else if (fanboysSocialListResults[0].equals(BlockListHelper.REQUEST_ALLOWED)) { // The resource request matched Fanboy's Social Blocking List's whitelist.
+ // Update the whitelist result string array tracker.
+ whitelistResultStringArray = new String[] {fanboysSocialListResults[0], fanboysSocialListResults[1], fanboysSocialListResults[2], fanboysSocialListResults[3],
+ fanboysSocialListResults[4], fanboysSocialListResults[5]};
+ }
+ }
+
+ // Add the request to the log because it hasn't been processed by any of the previous checks.
+ if (whitelistResultStringArray != null) { // The request was processed by a whitelist.
+ nestedScrollWebView.addResourceRequest(whitelistResultStringArray);
+ } else { // The request didn't match any blocklist entry. Log it as a default request.
+ nestedScrollWebView.addResourceRequest(new String[]{BlockListHelper.REQUEST_DEFAULT, url});
+ }
+
+ // The resource request has not been blocked. `return null` loads the requested resource.
+ return null;
+ }
+
+ // Handle HTTP authentication requests.
+ @Override
+ public void onReceivedHttpAuthRequest(WebView view, HttpAuthHandler handler, String host, String realm) {
+ // Store `handler` so it can be accessed from `onHttpAuthenticationCancel()` and `onHttpAuthenticationProceed()`.
+ httpAuthHandler = handler;
+
+ // Display the HTTP authentication dialog.
+ DialogFragment httpAuthenticationDialogFragment = HttpAuthenticationDialog.displayDialog(host, realm);
+ httpAuthenticationDialogFragment.show(getSupportFragmentManager(), getString(R.string.http_authentication));
+ }
+
+ @Override
+ public void onPageStarted(WebView view, String url, Bitmap favicon) {
+ // Reset the list of resource requests.
+ nestedScrollWebView.clearResourceRequests();
+
+ // Reset the requests counters.
+ nestedScrollWebView.resetRequestsCounters();
+
+ // If night mode is enabled, hide `mainWebView` until after the night mode CSS is applied.
+ if (nightMode) {
+ nestedScrollWebView.setVisibility(View.INVISIBLE);
+ }
+
+ // Hide the keyboard.
+ inputMethodManager.hideSoftInputFromWindow(nestedScrollWebView.getWindowToken(), 0);
+
+ // Check to see if Privacy Browser is waiting on Orbot.
+ if (!waitingForOrbot) { // Process the URL.
+ // The formatted URL string must be updated at the beginning of the load, so that if the user toggles JavaScript during the load the new website is reloaded.
+ formattedUrlString = url;
+
+ // Display the formatted URL text.
+ urlEditText.setText(formattedUrlString);
+
+ // Apply text highlighting to `urlTextBox`.
+ highlightUrlText();
+
+ // Get a URI for the current URL.
+ Uri currentUri = Uri.parse(formattedUrlString);
+
+ // Reset the list of host IP addresses.
+ nestedScrollWebView.clearCurrentIpAddresses();
+
+ // Get the IP addresses for the host.
+ new GetHostIpAddresses(activity, getSupportFragmentManager(), nestedScrollWebView).execute(currentUri.getHost());
+
+ // Apply any custom domain settings if the URL was loaded by navigating history.
+ if (navigatingHistory) {
+ // Apply the domain settings.
+ boolean userAgentChanged = applyDomainSettings(nestedScrollWebView, url, true, false);
+
+ // Reset `navigatingHistory`.
+ navigatingHistory = false;
+
+ // Manually load the URL if the user agent has changed, which will have caused the previous URL to be reloaded.
+ if (userAgentChanged) {
+ loadUrl(formattedUrlString);
+ }
+ }
+
+ // Replace Refresh with Stop if the menu item has been created. (The WebView typically begins loading before the menu items are instantiated.)
+ if (refreshMenuItem != null) {
+ // Set the title.
+ refreshMenuItem.setTitle(R.string.stop);
+
+ // If the icon is displayed in the AppBar, set it according to the theme.
+ if (displayAdditionalAppBarIcons) {
+ if (darkTheme) {
+ refreshMenuItem.setIcon(R.drawable.close_dark);
+ } else {
+ refreshMenuItem.setIcon(R.drawable.close_light);
+ }
+ }
+ }
+ }
+ }
+
+ // It is necessary to update `formattedUrlString` and `urlTextBox` after the page finishes loading because the final URL can change during load.
+ @Override
+ public void onPageFinished(WebView view, String url) {
+ // Reset the wide view port if it has been turned off by the waiting for Orbot message.
+ if (!waitingForOrbot) {
+ // Only use a wide view port if the URL starts with `http`, not for `file://` and `content://`.
+ nestedScrollWebView.getSettings().setUseWideViewPort(url.startsWith("http"));
+ }
+
+ // Flush any cookies to persistent storage. `CookieManager` has become very lazy about flushing cookies in recent versions.
+ if (firstPartyCookiesEnabled && Build.VERSION.SDK_INT >= 21) {
+ CookieManager.getInstance().flush();
+ }
+
+ // Update the Refresh menu item if it has been created.
+ if (refreshMenuItem != null) {
+ // Reset the Refresh title.
+ refreshMenuItem.setTitle(R.string.refresh);
+
+ // If the icon is displayed in the AppBar, reset it according to the theme.
+ if (displayAdditionalAppBarIcons) {
+ if (darkTheme) {
+ refreshMenuItem.setIcon(R.drawable.refresh_enabled_dark);
+ } else {
+ refreshMenuItem.setIcon(R.drawable.refresh_enabled_light);
+ }
+ }
+ }
+
+
+ // Clear the cache and history if Incognito Mode is enabled.
+ if (incognitoModeEnabled) {
+ // Clear the cache. `true` includes disk files.
+ nestedScrollWebView.clearCache(true);
+
+ // Clear the back/forward history.
+ nestedScrollWebView.clearHistory();
+
+ // Manually delete cache folders.
+ try {
+ // Delete the main cache directory.
+ Runtime.getRuntime().exec("rm -rf " + privateDataDirectoryString + "/cache");
+
+ // Delete the secondary `Service Worker` cache directory.
+ // A `String[]` must be used because the directory contains a space and `Runtime.exec` will not escape the string correctly otherwise.
+ Runtime.getRuntime().exec(new String[]{"rm", "-rf", privateDataDirectoryString + "/app_webview/Service Worker/"});
+ } catch (IOException e) {
+ // Do nothing if an error is thrown.
+ }
+ }
+
+ // Update the URL text box and apply domain settings if not waiting on Orbot.
+ if (!waitingForOrbot) {
+ // Check to see if `WebView` has set `url` to be `about:blank`.
+ if (url.equals("about:blank")) { // `WebView` is blank, so `formattedUrlString` should be `""` and `urlTextBox` should display a hint.
+ // Set `formattedUrlString` to `""`.
+ formattedUrlString = "";
+
+ urlEditText.setText(formattedUrlString);
+
+ // Request focus for `urlTextBox`.
+ urlEditText.requestFocus();
+
+ // Display the keyboard.
+ inputMethodManager.showSoftInput(urlEditText, 0);
+
+ // Apply the domain settings. This clears any settings from the previous domain.
+ applyDomainSettings(nestedScrollWebView, formattedUrlString, true, false);
+ } else { // `WebView` has loaded a webpage.
+ // Set the formatted URL string. Getting the URL from the WebView instead of using the one provided by `onPageFinished` makes websites like YouTube function correctly.
+ formattedUrlString = nestedScrollWebView.getUrl();
+
+ // Only update the URL text box if the user is not typing in it.
+ if (!urlEditText.hasFocus()) {
+ // Display the formatted URL text.
+ urlEditText.setText(formattedUrlString);
+
+ // Apply text highlighting to `urlTextBox`.
+ highlightUrlText();
+ }
+ }
+
+ // Check the current website information against any pinned domain information if the current IP addresses have been loaded.
+ if ((nestedScrollWebView.hasPinnedSslCertificate() || nestedScrollWebView.hasPinnedIpAddresses()) && nestedScrollWebView.hasCurrentIpAddresses() &&
+ !nestedScrollWebView.ignorePinnedDomainInformation()) {
+ CheckPinnedMismatchHelper.checkPinnedMismatch(getSupportFragmentManager(), nestedScrollWebView);
+ }
+ }
+ }
+
+ // Handle SSL Certificate errors.
+ @Override
+ public void onReceivedSslError(WebView view, SslErrorHandler handler, SslError error) {
+ // Get the current website SSL certificate.
+ SslCertificate currentWebsiteSslCertificate = error.getCertificate();
+
+ // Extract the individual pieces of information from the current website SSL certificate.
+ String currentWebsiteIssuedToCName = currentWebsiteSslCertificate.getIssuedTo().getCName();
+ String currentWebsiteIssuedToOName = currentWebsiteSslCertificate.getIssuedTo().getOName();
+ String currentWebsiteIssuedToUName = currentWebsiteSslCertificate.getIssuedTo().getUName();
+ String currentWebsiteIssuedByCName = currentWebsiteSslCertificate.getIssuedBy().getCName();
+ String currentWebsiteIssuedByOName = currentWebsiteSslCertificate.getIssuedBy().getOName();
+ String currentWebsiteIssuedByUName = currentWebsiteSslCertificate.getIssuedBy().getUName();
+ Date currentWebsiteSslStartDate = currentWebsiteSslCertificate.getValidNotBeforeDate();
+ Date currentWebsiteSslEndDate = currentWebsiteSslCertificate.getValidNotAfterDate();
+
+ // Proceed to the website if the current SSL website certificate matches the pinned domain certificate.
+ if (nestedScrollWebView.hasPinnedSslCertificate()) {
+ // Get the pinned SSL certificate.
+ ArrayList<Object> pinnedSslCertificateArrayList = nestedScrollWebView.getPinnedSslCertificate();
+
+ // Extract the arrays from the array list.
+ String[] pinnedSslCertificateStringArray = (String[]) pinnedSslCertificateArrayList.get(0);
+ Date[] pinnedSslCertificateDateArray = (Date[]) pinnedSslCertificateArrayList.get(1);
+
+ // Check if the current SSL certificate matches the pinned certificate.
+ if (currentWebsiteIssuedToCName.equals(pinnedSslCertificateStringArray[0]) && currentWebsiteIssuedToOName.equals(pinnedSslCertificateStringArray[1]) &&
+ currentWebsiteIssuedToUName.equals(pinnedSslCertificateStringArray[2]) && currentWebsiteIssuedByCName.equals(pinnedSslCertificateStringArray[3]) &&
+ currentWebsiteIssuedByOName.equals(pinnedSslCertificateStringArray[4]) && currentWebsiteIssuedByUName.equals(pinnedSslCertificateStringArray[5]) &&
+ currentWebsiteSslStartDate.equals(pinnedSslCertificateDateArray[0]) && currentWebsiteSslEndDate.equals(pinnedSslCertificateDateArray[1])) {
+
+ // An SSL certificate is pinned and matches the current domain certificate. Proceed to the website without displaying an error.
+ handler.proceed();
+ }
+ } else { // Either there isn't a pinned SSL certificate or it doesn't match the current website certificate.
+ // Store `handler` so it can be accesses from `onSslErrorCancel()` and `onSslErrorProceed()`.
+ sslErrorHandler = handler; // TODO. We need to pass this in instead of using a static variable. Because multiple could be displayed at once from different tabs.
+
+ // Display the SSL error `AlertDialog`.
+ DialogFragment sslCertificateErrorDialogFragment = SslCertificateErrorDialog.displayDialog(error);
+ sslCertificateErrorDialogFragment.show(getSupportFragmentManager(), getString(R.string.ssl_certificate_error));
+ }
+ }
+ });
+
+ // Check to see if this is the first page.
+ if (pageNumber == 0) {
+ // Set this nested scroll WebView as the current WebView.
+ currentWebView = nestedScrollWebView;
+
+ // Apply the app settings from the shared preferences.
+ applyAppSettings();
+
+ // Load the website if not waiting for Orbot to connect.
+ if (!waitingForOrbot) {
+ loadUrl(formattedUrlString);
+ }