- // Initialize the current SSL certificate variables.
- String currentWebsiteIssuedToCName = "";
- String currentWebsiteIssuedToOName = "";
- String currentWebsiteIssuedToUName = "";
- String currentWebsiteIssuedByCName = "";
- String currentWebsiteIssuedByOName = "";
- String currentWebsiteIssuedByUName = "";
- Date currentWebsiteSslStartDate = null;
- Date currentWebsiteSslEndDate = null;
-
-
- // Extract the individual pieces of information from the current website SSL certificate if it is not null.
- if (sslCertificate != null) {
- currentWebsiteIssuedToCName = sslCertificate.getIssuedTo().getCName();
- currentWebsiteIssuedToOName = sslCertificate.getIssuedTo().getOName();
- currentWebsiteIssuedToUName = sslCertificate.getIssuedTo().getUName();
- currentWebsiteIssuedByCName = sslCertificate.getIssuedBy().getCName();
- currentWebsiteIssuedByOName = sslCertificate.getIssuedBy().getOName();
- currentWebsiteIssuedByUName = sslCertificate.getIssuedBy().getUName();
- currentWebsiteSslStartDate = sslCertificate.getValidNotBeforeDate();
- currentWebsiteSslEndDate = sslCertificate.getValidNotAfterDate();
- }
-
- // Initialize `String` variables to store the SSL certificate dates. `Strings` are needed to compare the values below, which doesn't work with `Dates` if they are `null`.
- String currentWebsiteSslStartDateString = "";
- String currentWebsiteSslEndDateString = "";
- String pinnedDomainSslStartDateString = "";
- String pinnedDomainSslEndDateString = "";
-
- // Convert the `Dates` to `Strings` if they are not `null`.
- if (currentWebsiteSslStartDate != null) {
- currentWebsiteSslStartDateString = currentWebsiteSslStartDate.toString();
- }
-
- if (currentWebsiteSslEndDate != null) {
- currentWebsiteSslEndDateString = currentWebsiteSslEndDate.toString();
- }
-
- if (pinnedDomainSslStartDate != null) {
- pinnedDomainSslStartDateString = pinnedDomainSslStartDate.toString();
- }
-
- if (pinnedDomainSslEndDate != null) {
- pinnedDomainSslEndDateString = pinnedDomainSslEndDate.toString();
- }
-
- // Check to see if the pinned SSL certificate matches the current website certificate.
- if (!currentWebsiteIssuedToCName.equals(pinnedDomainSslIssuedToCNameString) || !currentWebsiteIssuedToOName.equals(pinnedDomainSslIssuedToONameString) || !currentWebsiteIssuedToUName.equals(pinnedDomainSslIssuedToUNameString) ||
- !currentWebsiteIssuedByCName.equals(pinnedDomainSslIssuedByCNameString) || !currentWebsiteIssuedByOName.equals(pinnedDomainSslIssuedByONameString) || !currentWebsiteIssuedByUName.equals(pinnedDomainSslIssuedByUNameString) ||
- !currentWebsiteSslStartDateString.equals(pinnedDomainSslStartDateString) || !currentWebsiteSslEndDateString.equals(pinnedDomainSslEndDateString)) { // The pinned SSL certificate doesn't match the current domain certificate.
- //Display the pinned SSL certificate mismatch `AlertDialog`.
- AppCompatDialogFragment pinnedSslCertificateMismatchDialogFragment = new PinnedSslCertificateMismatchDialog();
- pinnedSslCertificateMismatchDialogFragment.show(getSupportFragmentManager(), getString(R.string.ssl_certificate_mismatch));
- }
- }
- }
- }
-
- // 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 (pinnedDomainSslCertificate &&
- currentWebsiteIssuedToCName.equals(pinnedDomainSslIssuedToCNameString) && currentWebsiteIssuedToOName.equals(pinnedDomainSslIssuedToONameString) && currentWebsiteIssuedToUName.equals(pinnedDomainSslIssuedToUNameString) &&
- currentWebsiteIssuedByCName.equals(pinnedDomainSslIssuedByCNameString) && currentWebsiteIssuedByOName.equals(pinnedDomainSslIssuedByONameString) && currentWebsiteIssuedByUName.equals(pinnedDomainSslIssuedByUNameString) &&
- currentWebsiteSslStartDate.equals(pinnedDomainSslStartDate) && currentWebsiteSslEndDate.equals(pinnedDomainSslEndDate)) { // 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;
-
- // Display the SSL error `AlertDialog`.
- AppCompatDialogFragment sslCertificateErrorDialogFragment = SslCertificateErrorDialog.displayDialog(error);
- sslCertificateErrorDialogFragment.show(getSupportFragmentManager(), getString(R.string.ssl_certificate_error));
- }
- }
- });
-
- // Get a handle for the progress bar.
- final ProgressBar progressBar = (ProgressBar) findViewById(R.id.progress_bar);
-
- mainWebView.setWebChromeClient(new WebChromeClient() {
- // Update the progress bar when a page is loading.
- @Override
- public void onProgressChanged(WebView view, int progress) {
- // Inject the night mode CSS if night mode is enabled.
- if (nightMode) {
- // `background-color: #212121` sets the background to be dark gray. `color: #BDBDBD` sets the text color to be light gray. `box-shadow: none` removes a lower underline on links used by WordPress.
- // `text-decoration: none` removes all text underlines. `text-shadow: none` removes text shadows, which usually have a hard coded color. `border: none` removes all borders, which can also be used to underline text.
- // `a {color: #1565C0}` sets links to be a dark blue. `!important` takes precedent over any existing sub-settings.
- mainWebView.evaluateJavascript("(function() {var parent = document.getElementsByTagName('head').item(0); var style = document.createElement('style'); style.type = 'text/css'; style.innerHTML = '" +
- "* {background-color: #212121 !important; color: #BDBDBD !important; box-shadow: none !important; text-decoration: none !important; text-shadow: none !important; border: none !important;}" +
- "a {color: #1565C0 !important;}" +
- "'; parent.appendChild(style)})()", new ValueCallback<String>() {
- @Override
- public void onReceiveValue(String value) {
- // Initialize a `Handler` to display `mainWebView`.
- Handler displayWebViewHandler = new Handler();
-
- // Setup a `Runnable` to display `mainWebView` after a delay to allow the CSS to be applied.
- Runnable displayWebViewRunnable = new Runnable() {
- public void run() {
- // Only display `mainWebView` if the progress bar is one. This prevents the display of the `WebView` while it is still loading.
- if (progressBar.getVisibility() == View.GONE) {
- mainWebView.setVisibility(View.VISIBLE);
- }
- }
- };
-
- // Use `displayWebViewHandler` to delay the displaying of `mainWebView` for 500 milliseconds.
- displayWebViewHandler.postDelayed(displayWebViewRunnable, 500);
- }
- });
- }
-
- progressBar.setProgress(progress);
- if (progress < 100) {
- // Show the progress bar.
- progressBar.setVisibility(View.VISIBLE);
- } else {
- // Hide the progress bar.
- progressBar.setVisibility(View.GONE);
-
- // Display `mainWebView` if night mode is disabled.
- // Because of a race condition between `applyDomainSettings` and `onPageStarted`, when night mode is set by domain settings the `WebView` may be hidden even if night mode is not currently enabled.
- if (!nightMode) {
- mainWebView.setVisibility(View.VISIBLE);
- }
-
- //Stop the `SwipeToRefresh` indicator if it is running
- swipeRefreshLayout.setRefreshing(false);
- }
- }
-
- // Set the favorite icon when it changes.
- @Override
- public void onReceivedIcon(WebView view, Bitmap icon) {
- // Only update the favorite icon if the website has finished loading.
- if (progressBar.getVisibility() == View.GONE) {
- // Save a copy of the favorite icon.
- favoriteIconBitmap = icon;
-
- // Place the favorite icon in the appBar.
- favoriteIconImageView.setImageBitmap(Bitmap.createScaledBitmap(icon, 64, 64, true));
- }
- }
-
- // Save a copy of the title when it changes.
- @Override
- public void onReceivedTitle(WebView view, String title) {
- // Save a copy of the title.
- webViewTitle = title;
- }
-
- // Enter full screen video
- @Override
- public void onShowCustomView(View view, CustomViewCallback callback) {
- // Pause the ad if this is the free flavor.
- if (BuildConfig.FLAVOR.contentEquals("free")) {
- BannerAd.pauseAd(adView);
- }
-
- // Remove the translucent overlays.
- getWindow().clearFlags(WindowManager.LayoutParams.FLAG_TRANSLUCENT_STATUS);
-
- // Remove the translucent status bar overlay on the `Drawer Layout`, which is special and needs its own command.
- drawerLayout.setSystemUiVisibility(View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN);
-
- /* SYSTEM_UI_FLAG_FULLSCREEN hides the status bar at the top of the screen.
- * SYSTEM_UI_FLAG_HIDE_NAVIGATION hides the navigation bar on the bottom or right of the screen.
- * SYSTEM_UI_FLAG_IMMERSIVE_STICKY makes the status and navigation bars translucent and automatically rehides them after they are shown.
- */
- rootCoordinatorLayout.setSystemUiVisibility(View.SYSTEM_UI_FLAG_FULLSCREEN | View.SYSTEM_UI_FLAG_HIDE_NAVIGATION | View.SYSTEM_UI_FLAG_IMMERSIVE_STICKY);
-
- // Set `rootCoordinatorLayout` to fill the entire screen.
- rootCoordinatorLayout.setFitsSystemWindows(false);
-
- // Add `view` to `fullScreenVideoFrameLayout` and display it on the screen.
- fullScreenVideoFrameLayout.addView(view);
- fullScreenVideoFrameLayout.setVisibility(View.VISIBLE);
- }
-
- // Exit full screen video
- public void onHideCustomView() {
- // Hide `fullScreenVideoFrameLayout`.
- fullScreenVideoFrameLayout.removeAllViews();
- fullScreenVideoFrameLayout.setVisibility(View.GONE);
-
- // Add the translucent status flag. This also resets `drawerLayout's` `View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN`.
- getWindow().addFlags(WindowManager.LayoutParams.FLAG_TRANSLUCENT_STATUS);
-
- // Set `rootCoordinatorLayout` to fit inside the status and navigation bars. This also clears the `SYSTEM_UI` flags.
- rootCoordinatorLayout.setFitsSystemWindows(true);
-
- // Show the ad if this is the free flavor.
- if (BuildConfig.FLAVOR.contentEquals("free")) {
- // Reload the ad. Because the screen may have rotated, we need to use `reloadAfterRotate`.
- BannerAd.reloadAfterRotate(adView, getApplicationContext(), getString(R.string.ad_id));
-
- // Reinitialize the `adView` variable, as the `View` will have been removed and re-added by `BannerAd.reloadAfterRotate()`.
- adView = findViewById(R.id.adview);
- }
- }
- });
-
- // Register `mainWebView` for a context menu. This is used to see link targets and download images.
- registerForContextMenu(mainWebView);
-
- // Allow the downloading of files.
- mainWebView.setDownloadListener(new DownloadListener() {
- @Override
- public void onDownloadStart(String url, String userAgent, String contentDisposition, String mimetype, long contentLength) {
- // Show the `DownloadFileDialog` `AlertDialog` and name this instance `@string/download`.
- AppCompatDialogFragment downloadFileDialogFragment = DownloadFileDialog.fromUrl(url, contentDisposition, contentLength);
- downloadFileDialogFragment.show(getSupportFragmentManager(), getString(R.string.download));
- }
- });
-
- // Allow pinch to zoom.
- mainWebView.getSettings().setBuiltInZoomControls(true);
-
- // Hide zoom controls.
- mainWebView.getSettings().setDisplayZoomControls(false);
-
- // Set `mainWebView` to use a wide viewport. Otherwise, some web pages will be scrunched and some content will render outside the screen.
- mainWebView.getSettings().setUseWideViewPort(true);
-
- // Set `mainWebView` to load in overview mode (zoomed out to the maximum width).
- mainWebView.getSettings().setLoadWithOverviewMode(true);
-
- // Explicitly disable geolocation.
- mainWebView.getSettings().setGeolocationEnabled(false);
-
- // Initialize cookieManager.
- cookieManager = CookieManager.getInstance();
-
- // Replace the header that `WebView` creates for `X-Requested-With` with a null value. The default value is the application ID (com.stoutner.privacybrowser.standard).
- customHeaders.put("X-Requested-With", "");
-
- // Initialize the default preference values the first time the program is run. `this` is the context. `false` keeps this command from resetting any current preferences back to default.
- PreferenceManager.setDefaultValues(this, R.xml.preferences, false);