]> gitweb.stoutner.com Git - PrivacyBrowserAndroid.git/blobdiff - app/src/main/java/com/stoutner/privacybrowser/activities/DomainsActivity.java
Implement IP Address Pinning. https://redmine.stoutner.com/issues/212
[PrivacyBrowserAndroid.git] / app / src / main / java / com / stoutner / privacybrowser / activities / DomainsActivity.java
index a56e7184b6106f7277e6675dade66f4339ccd323..7dbb6bf3e827600a73ede4766241cb9ee8b589ba 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright © 2017-2018 Soren Stoutner <soren@stoutner.com>.
+ * Copyright © 2017-2019 Soren Stoutner <soren@stoutner.com>.
  *
  * This file is part of Privacy Browser <https://www.stoutner.com/privacy-browser>.
  *
@@ -19,6 +19,7 @@
 
 package com.stoutner.privacybrowser.activities;
 
+import android.app.Activity;
 import android.content.Context;
 import android.content.Intent;
 import android.content.res.Resources;
@@ -54,6 +55,8 @@ import com.stoutner.privacybrowser.fragments.DomainSettingsFragment;
 import com.stoutner.privacybrowser.fragments.DomainsListFragment;
 import com.stoutner.privacybrowser.helpers.DomainsDatabaseHelper;
 
+import java.util.Objects;
+
 public class DomainsActivity extends AppCompatActivity implements AddDomainDialog.AddDomainListener {
     // `twoPanedMode` is public static so it can be accessed from `DomainsListFragment`.  It is also used in `onCreate()`, `onCreateOptionsMenu()`, and `populateDomainsListView()`.
     public static boolean twoPanedMode;
@@ -70,13 +73,16 @@ public class DomainsActivity extends AppCompatActivity implements AddDomainDialo
     // `dismissingSnackbar` is public static so it can be accessed from `DomainsListFragment`.  It is also used in `onOptionsItemSelected()`.
     public static boolean dismissingSnackbar;
 
+    // `closeActivityAfterDismissingSnackbar` is used in `onOptionsItemSelected()`, and `onBackPressed()`.
+    private boolean closeActivityAfterDismissingSnackbar;
+
     // `context` is used in `onCreate()`, `onOptionsItemSelected()`, and `onAddDomain()`.
     private Context context;
 
     // `supportFragmentManager` is used in `onCreate()` and `onCreateOptionsMenu()`.
     private FragmentManager supportFragmentManager;
 
-    // `domainsDatabaseHelper` is used in `onCreate()` and `saveDomainSettings()`.
+    // `domainsDatabaseHelper` is used in `onCreate()`, `saveDomainSettings()`, and `onDestroy()`.
     private static DomainsDatabaseHelper domainsDatabaseHelper;
 
     // `domainsListView` is used in `onCreate()` and `populateDomainsList()`.
@@ -155,12 +161,12 @@ public class DomainsActivity extends AppCompatActivity implements AddDomainDialo
         final Toolbar domainsAppBar = findViewById(R.id.domains_toolbar);
         setSupportActionBar(domainsAppBar);
 
-        // Display the home arrow on `SupportActionBar`.
+        // Display the home arrow on the support action bar.
         ActionBar appBar = getSupportActionBar();
         assert appBar != null;// This assert removes the incorrect warning in Android Studio on the following line that `appBar` might be null.
         appBar.setDisplayHomeAsUpEnabled(true);
 
-        // Initialize the database handler.  The two `nulls` do not specify the database name or a `CursorFactory`.  The `0` specifies the database version, but that is ignored and set instead using a constant in `DomainsDatabaseHelper`.
+        // Initialize the database handler.  The `0` specifies the database version, but that is ignored and set instead using a constant in `DomainsDatabaseHelper`.
         domainsDatabaseHelper = new DomainsDatabaseHelper(context, null, null, 0);
 
         // Determine if we are in two pane mode.  `domain_settings_fragment_container` does not exist on devices with a width less than 900dp.
@@ -218,7 +224,7 @@ public class DomainsActivity extends AppCompatActivity implements AddDomainDialo
                 deleteMenuItem.setVisible(true);
 
                 // Hide `add_domain_fab`.
-                addDomainFAB.setVisibility(View.GONE);
+                addDomainFAB.hide();
 
                 // Display `domainSettingsFragment`.
                 supportFragmentManager.beginTransaction().replace(R.id.domains_listview_fragment_container, domainSettingsFragment).commit();
@@ -249,7 +255,7 @@ public class DomainsActivity extends AppCompatActivity implements AddDomainDialo
                     deleteMenuItem.setVisible(true);
 
                     // Hide `add_domain_fab`.
-                    addDomainFAB.setVisibility(View.GONE);
+                    addDomainFAB.hide();
 
                     // Display `domainSettingsFragment`.
                     supportFragmentManager.beginTransaction().replace(R.id.domains_listview_fragment_container, domainSettingsFragment).commit();
@@ -284,17 +290,11 @@ public class DomainsActivity extends AppCompatActivity implements AddDomainDialo
 
                     // Dismiss the undo delete `SnackBar` if it is shown.
                     if (undoDeleteSnackbar != null && undoDeleteSnackbar.isShown()) {
-                        undoDeleteSnackbar.dismiss();
-
-                        // Create a `Runnable` to return to the main activity.
-                        Runnable navigateHomeRunnable = () -> {
-                            // Go home.
-                            NavUtils.navigateUpFromSameTask(this);
-                        };
+                        // Set the close flag.
+                        closeActivityAfterDismissingSnackbar = true;
 
-                        // Navigate home after 300 milliseconds to make sure that the previous domain has been deleted from the database.
-                        Handler handler = new Handler();
-                        handler.postDelayed(navigateHomeRunnable, 300);
+                        // Dismiss the snackbar.
+                        undoDeleteSnackbar.dismiss();
                     } else {
                         // Go home.
                         NavUtils.navigateUpFromSameTask(this);
@@ -317,25 +317,19 @@ public class DomainsActivity extends AppCompatActivity implements AddDomainDialo
                     // Populate the list of domains.  `-1` highlights the first domain if in two-paned mode.  It has no effect in single-paned mode.
                     populateDomainsListView(-1);
 
-                    // Display the add domain FAB.
-                    addDomainFAB.setVisibility(View.VISIBLE);
+                    // Show the add domain FAB.
+                    addDomainFAB.show();
 
                     // Hide the delete menu item.
                     deleteMenuItem.setVisible(false);
                 } else {  // The device is in single-paned mode and `DomainsListFragment` is displayed.
                     // Dismiss the undo delete `SnackBar` if it is shown.
                     if (undoDeleteSnackbar != null && undoDeleteSnackbar.isShown()) {
-                        undoDeleteSnackbar.dismiss();
+                        // Set the close flag.
+                        closeActivityAfterDismissingSnackbar = true;
 
-                        // Create a `Runnable` to return to the main activity.
-                        Runnable navigateHomeRunnable = () -> {
-                            // Go home.
-                            NavUtils.navigateUpFromSameTask(this);
-                        };
-
-                        // Navigate home after 300 milliseconds to make sure that the previous domain has been deleted from the database.
-                        Handler handler = new Handler();
-                        handler.postDelayed(navigateHomeRunnable, 300);
+                        // Dismiss the snackbar.
+                        undoDeleteSnackbar.dismiss();
                     } else {
                         // Go home.
                         NavUtils.navigateUpFromSameTask(this);
@@ -360,15 +354,15 @@ public class DomainsActivity extends AppCompatActivity implements AddDomainDialo
                     deleteMenuItem.setIcon(R.drawable.delete_blue);
 
                     // Remove the domain settings fragment.
-                    supportFragmentManager.beginTransaction().remove(supportFragmentManager.findFragmentById(R.id.domain_settings_fragment_container)).commit();
+                    supportFragmentManager.beginTransaction().remove(Objects.requireNonNull(supportFragmentManager.findFragmentById(R.id.domain_settings_fragment_container))).commit();
                 } else {  // Single-paned mode.
                     // Display `DomainsListFragment`.
                     DomainsListFragment domainsListFragment = new DomainsListFragment();
                     supportFragmentManager.beginTransaction().replace(R.id.domains_listview_fragment_container, domainsListFragment).commit();
                     supportFragmentManager.executePendingTransactions();
 
-                    // Display `addDomainFAB`.
-                    addDomainFAB.setVisibility(View.VISIBLE);
+                    // Show the add domain FAB.
+                    addDomainFAB.show();
 
                     // Hide `deleteMenuItem`.
                     deleteMenuItem.setVisible(false);
@@ -400,6 +394,9 @@ public class DomainsActivity extends AppCompatActivity implements AddDomainDialo
                 // Update the `ListView`.
                 domainsListView.setAdapter(domainsPendingDeleteCursorAdapter);
 
+                // Get a handle for the activity.
+                Activity activity = this;
+
                 // Display a `Snackbar`.
                 undoDeleteSnackbar = Snackbar.make(domainsListView, R.string.domain_deleted, Snackbar.LENGTH_LONG)
                         .setAction(R.string.undo, (View v) -> {
@@ -456,9 +453,8 @@ public class DomainsActivity extends AppCompatActivity implements AddDomainDialo
                                             // Display `domainSettingsFragment`.
                                             supportFragmentManager.beginTransaction().replace(R.id.domains_listview_fragment_container, domainSettingsFragment).commit();
 
-                                            // Hide `add_domain_fab`.
-                                            FloatingActionButton addDomainFAB = findViewById(R.id.add_domain_fab);
-                                            addDomainFAB.setVisibility(View.GONE);
+                                            // Hide the add domain FAB.
+                                            addDomainFAB.hide();
 
                                             // Show and enable `deleteMenuItem`.
                                             deleteMenuItem.setVisible(true);
@@ -473,7 +469,7 @@ public class DomainsActivity extends AppCompatActivity implements AddDomainDialo
                                         // Delete the selected domain.
                                         domainsDatabaseHelper.deleteDomain(databaseIdToDelete);
 
-                                        // enable `deleteMenuItem` if the system was waiting for a `Snackbar` to be dismissed.
+                                        // Enable the delete menu item if the system was waiting for a snackbar to be dismissed.
                                         if (dismissingSnackbar) {
                                             // Create a `Runnable` to enable the delete menu item.
                                             Runnable enableDeleteMenuItemRunnable = () -> {
@@ -497,14 +493,23 @@ public class DomainsActivity extends AppCompatActivity implements AddDomainDialo
                                                 dismissingSnackbar = false;
                                             };
 
-                                            // Run `enableDeleteMenuItemRunnable` after 100 milliseconds to make sure that the previous domain has been deleted from the database.
+                                            // Enable the delete menu icon after 100 milliseconds to make sure that the previous domain has been deleted from the database.
                                             Handler handler = new Handler();
                                             handler.postDelayed(enableDeleteMenuItemRunnable, 100);
                                         }
+
+                                        // Close the activity if back was pressed.
+                                        if (closeActivityAfterDismissingSnackbar) {
+                                            // Go home.
+                                            NavUtils.navigateUpFromSameTask(activity);
+                                        }
+
                                         break;
                                 }
                             }
                         });
+
+                // Show the Snackbar.
                 undoDeleteSnackbar.show();
                 break;
         }
@@ -542,14 +547,11 @@ public class DomainsActivity extends AppCompatActivity implements AddDomainDialo
 
             // Dismiss the undo delete SnackBar if it is shown.
             if ((undoDeleteSnackbar != null) && undoDeleteSnackbar.isShown()) {
-                undoDeleteSnackbar.dismiss();
-
-                // Create a runnable to return to the main activity.
-                Runnable navigateHomeRunnable = super::onBackPressed;
+                // Set the close flag.
+                closeActivityAfterDismissingSnackbar = true;
 
-                // Navigate home after 300 milliseconds to make sure that the previous domain has been deleted from the database.
-                Handler handler = new Handler();
-                handler.postDelayed(navigateHomeRunnable, 300);
+                // Dismiss the snackbar.
+                undoDeleteSnackbar.dismiss();
             } else {
                 // Pass `onBackPressed()` to the system.
                 super.onBackPressed();
@@ -572,22 +574,19 @@ public class DomainsActivity extends AppCompatActivity implements AddDomainDialo
             // Populate the list of domains.  `-1` highlights the first domain if in two-paned mode.  It has no effect in single-paned mode.
             populateDomainsListView(-1);
 
-            // Display the add domain FAB.
-            addDomainFAB.setVisibility(View.VISIBLE);
+            // Show the add domain FAB.
+            addDomainFAB.show();
 
             // Hide the delete menu item.
             deleteMenuItem.setVisible(false);
         } else {  // The device is in single-paned mode and the domain list fragment is displayed.
             // Dismiss the undo delete SnackBar if it is shown.
             if ((undoDeleteSnackbar != null) && undoDeleteSnackbar.isShown()) {
-                undoDeleteSnackbar.dismiss();
+                // Set the close flag.
+                closeActivityAfterDismissingSnackbar = true;
 
-                // Create a runnable to return to the main activity.
-                Runnable navigateHomeRunnable = super::onBackPressed;
-
-                // Navigate home after 300 milliseconds to make sure that the previous domain has been deleted from the database.
-                Handler handler = new Handler();
-                handler.postDelayed(navigateHomeRunnable, 300);
+                // Dismiss the snackbar.
+                undoDeleteSnackbar.dismiss();
             } else {
                 // Pass `onBackPressed()` to the system.
                 super.onBackPressed();
@@ -613,8 +612,8 @@ public class DomainsActivity extends AppCompatActivity implements AddDomainDialo
         if (twoPanedMode) {  // The device in in two-paned mode.
             populateDomainsListView(currentDomainDatabaseId);
         } else {  // The device is in single-paned mode.
-            // Hide `add_domain_fab`.
-            addDomainFAB.setVisibility(View.GONE);
+            // Hide the add domain FAB.
+            addDomainFAB.hide();
 
             // Show and enable `deleteMenuItem`.
             DomainsActivity.deleteMenuItem.setVisible(true);
@@ -635,26 +634,28 @@ public class DomainsActivity extends AppCompatActivity implements AddDomainDialo
     public void saveDomainSettings(View view, Resources resources) {
         // Get handles for the domain settings.
         EditText domainNameEditText = view.findViewById(R.id.domain_settings_name_edittext);
-        Switch javaScriptSwitch = view.findViewById(R.id.domain_settings_javascript_switch);
-        Switch firstPartyCookiesSwitch = view.findViewById(R.id.domain_settings_first_party_cookies_switch);
-        Switch thirdPartyCookiesSwitch = view.findViewById(R.id.domain_settings_third_party_cookies_switch);
-        Switch domStorageSwitch = view.findViewById(R.id.domain_settings_dom_storage_switch);
-        Switch formDataSwitch = view.findViewById(R.id.domain_settings_form_data_switch);  // Form data can be removed once the minimum API >= 26.
-        Switch easyListSwitch = view.findViewById(R.id.domain_settings_easylist_switch);
-        Switch easyPrivacySwitch = view.findViewById(R.id.domain_settings_easyprivacy_switch);
-        Switch fanboysAnnoyanceSwitch = view.findViewById(R.id.domain_settings_fanboys_annoyance_list_switch);
-        Switch fanboysSocialBlockingSwitch = view.findViewById(R.id.domain_settings_fanboys_social_blocking_list_switch);
-        Switch ultraPrivacySwitch = view.findViewById(R.id.domain_settings_ultraprivacy_switch);
-        Switch blockAllThirdPartyRequestsSwitch = view.findViewById(R.id.domain_settings_block_all_third_party_requests_switch);
-        Spinner userAgentSpinner = view.findViewById(R.id.domain_settings_user_agent_spinner);
-        EditText customUserAgentEditText = view.findViewById(R.id.domain_settings_custom_user_agent_edittext);
-        Spinner fontSizeSpinner = view.findViewById(R.id.domain_settings_font_size_spinner);
-        Spinner swipeToRefreshSpinner = view.findViewById(R.id.domain_settings_swipe_to_refresh_spinner);
-        Spinner displayWebpageImagesSpinner = view.findViewById(R.id.domain_settings_display_webpage_images_spinner);
-        Spinner nightModeSpinner = view.findViewById(R.id.domain_settings_night_mode_spinner);
-        Switch pinnedSslCertificateSwitch = view.findViewById(R.id.domain_settings_pinned_ssl_certificate_switch);
-        RadioButton savedSslCertificateRadioButton = view.findViewById(R.id.saved_ssl_certificate_radiobutton);
+        Switch javaScriptSwitch = view.findViewById(R.id.javascript_switch);
+        Switch firstPartyCookiesSwitch = view.findViewById(R.id.first_party_cookies_switch);
+        Switch thirdPartyCookiesSwitch = view.findViewById(R.id.third_party_cookies_switch);
+        Switch domStorageSwitch = view.findViewById(R.id.dom_storage_switch);
+        Switch formDataSwitch = view.findViewById(R.id.form_data_switch);  // Form data can be removed once the minimum API >= 26.
+        Switch easyListSwitch = view.findViewById(R.id.easylist_switch);
+        Switch easyPrivacySwitch = view.findViewById(R.id.easyprivacy_switch);
+        Switch fanboysAnnoyanceSwitch = view.findViewById(R.id.fanboys_annoyance_list_switch);
+        Switch fanboysSocialBlockingSwitch = view.findViewById(R.id.fanboys_social_blocking_list_switch);
+        Switch ultraPrivacySwitch = view.findViewById(R.id.ultraprivacy_switch);
+        Switch blockAllThirdPartyRequestsSwitch = view.findViewById(R.id.block_all_third_party_requests_switch);
+        Spinner userAgentSpinner = view.findViewById(R.id.user_agent_spinner);
+        EditText customUserAgentEditText = view.findViewById(R.id.custom_user_agent_edittext);
+        Spinner fontSizeSpinner = view.findViewById(R.id.font_size_spinner);
+        Spinner swipeToRefreshSpinner = view.findViewById(R.id.swipe_to_refresh_spinner);
+        Spinner displayWebpageImagesSpinner = view.findViewById(R.id.display_webpage_images_spinner);
+        Spinner nightModeSpinner = view.findViewById(R.id.night_mode_spinner);
+        Switch pinnedSslCertificateSwitch = view.findViewById(R.id.pinned_ssl_certificate_switch);
         RadioButton currentWebsiteCertificateRadioButton = view.findViewById(R.id.current_website_certificate_radiobutton);
+        Switch pinnedIpAddressesSwitch = view.findViewById(R.id.pinned_ip_addresses_switch);
+        RadioButton currentIpAddressesRadioButton = view.findViewById(R.id.current_ip_addresses_radiobutton);
+        TextView currentIpAddressesTextView = view.findViewById(R.id.current_ip_addresses_textview);
 
         // Extract the data for the domain settings.
         String domainNameString = domainNameEditText.getText().toString();
@@ -675,6 +676,7 @@ public class DomainsActivity extends AppCompatActivity implements AddDomainDialo
         int displayWebpageImagesInt = displayWebpageImagesSpinner.getSelectedItemPosition();
         int nightModeInt = nightModeSpinner.getSelectedItemPosition();
         boolean pinnedSslCertificate = pinnedSslCertificateSwitch.isChecked();
+        boolean pinnedIpAddress = pinnedIpAddressesSwitch.isChecked();
 
         // Initialize the user agent name string.
         String userAgentName;
@@ -703,12 +705,12 @@ public class DomainsActivity extends AppCompatActivity implements AddDomainDialo
         int fontSizeInt = Integer.parseInt(resources.getStringArray(R.array.domain_settings_font_size_entry_values)[fontSizePosition]);
 
         // Save the domain settings.
-        if (savedSslCertificateRadioButton.isChecked()) {  // The current certificate is being used.
-            // Update the database except for the certificate.
-            domainsDatabaseHelper.updateDomainExceptCertificate(DomainsActivity.currentDomainDatabaseId, domainNameString, javaScriptEnabled, firstPartyCookiesEnabled, thirdPartyCookiesEnabled,
+        domainsDatabaseHelper.updateDomain(DomainsActivity.currentDomainDatabaseId, domainNameString, javaScriptEnabled, firstPartyCookiesEnabled, thirdPartyCookiesEnabled,
                     domStorageEnabled, formDataEnabled, easyListEnabled, easyPrivacyEnabled, fanboysAnnoyanceEnabled, fanboysSocialBlockingEnabled, ultraPrivacyEnabled, blockAllThirdPartyRequests,
-                    userAgentName, fontSizeInt, swipeToRefreshInt, nightModeInt, displayWebpageImagesInt, pinnedSslCertificate);
-        } else if (currentWebsiteCertificateRadioButton.isChecked()) {  // The certificate is being updated with the current website certificate.
+                    userAgentName, fontSizeInt, swipeToRefreshInt, nightModeInt, displayWebpageImagesInt, pinnedSslCertificate, pinnedIpAddress);
+
+        // Update the pinned SSL certificate if a new one is checked.
+        if (currentWebsiteCertificateRadioButton.isChecked()) {
             // Get the current website SSL certificate.
             SslCertificate currentWebsiteSslCertificate = MainWebViewActivity.sslCertificate;
 
@@ -723,16 +725,17 @@ public class DomainsActivity extends AppCompatActivity implements AddDomainDialo
             long endDateLong = currentWebsiteSslCertificate.getValidNotAfterDate().getTime();
 
             // Update the database.
-            domainsDatabaseHelper.updateDomainWithCertificate(currentDomainDatabaseId, domainNameString, javaScriptEnabled, firstPartyCookiesEnabled, thirdPartyCookiesEnabled, domStorageEnabled,
-                    formDataEnabled, easyListEnabled, easyPrivacyEnabled, fanboysAnnoyanceEnabled, fanboysSocialBlockingEnabled, ultraPrivacyEnabled, blockAllThirdPartyRequests, userAgentName, fontSizeInt,
-                    swipeToRefreshInt, nightModeInt, displayWebpageImagesInt, pinnedSslCertificate, issuedToCommonName, issuedToOrganization, issuedToOrganizationalUnit, issuedByCommonName,
-                    issuedByOrganization, issuedByOrganizationalUnit, startDateLong, endDateLong);
-
-        } else {  // No certificate is selected.
-            // Update the database, with PINNED_SSL_CERTIFICATE set to false.
-            domainsDatabaseHelper.updateDomainExceptCertificate(currentDomainDatabaseId, domainNameString, javaScriptEnabled, firstPartyCookiesEnabled, thirdPartyCookiesEnabled, domStorageEnabled,
-                    formDataEnabled, easyListEnabled, easyPrivacyEnabled, fanboysAnnoyanceEnabled, fanboysSocialBlockingEnabled, ultraPrivacyEnabled, blockAllThirdPartyRequests, userAgentName, fontSizeInt,
-                    swipeToRefreshInt, nightModeInt, displayWebpageImagesInt,false);
+            domainsDatabaseHelper.updatePinnedSslCertificate(currentDomainDatabaseId, issuedToCommonName, issuedToOrganization, issuedToOrganizationalUnit, issuedByCommonName, issuedByOrganization,
+                    issuedByOrganizationalUnit, startDateLong, endDateLong);
+        }
+
+        // Update the pinned IP addresses if new ones are checked.
+        if (currentIpAddressesRadioButton.isChecked()) {
+            // Get the current IP addresses.
+            String currentIpAddresses = currentIpAddressesTextView.getText().toString();
+
+            // Update the database.
+            domainsDatabaseHelper.updatePinnedIpAddresses(currentDomainDatabaseId, currentIpAddresses);
         }
     }
 
@@ -815,4 +818,13 @@ public class DomainsActivity extends AppCompatActivity implements AddDomainDialo
             deleteMenuItem.setIcon(R.drawable.delete_blue);
         }
     }
+
+    @Override
+    public void onDestroy() {
+        // Close the domains database helper.
+        domainsDatabaseHelper.close();
+
+        // Run the default commands.
+        super.onDestroy();
+    }
 }
\ No newline at end of file