/*
- * 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>.
*
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();
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();
// 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);
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);
// 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);
// 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);
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);
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();
int displayWebpageImagesInt = displayWebpageImagesSpinner.getSelectedItemPosition();
int nightModeInt = nightModeSpinner.getSelectedItemPosition();
boolean pinnedSslCertificate = pinnedSslCertificateSwitch.isChecked();
+ boolean pinnedIpAddress = pinnedIpAddressesSwitch.isChecked();
// Initialize the user agent name string.
String userAgentName;
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;
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);
}
}
/*
- * Copyright © 2018 Soren Stoutner <soren@stoutner.com>.
+ * Copyright © 2018-2019 Soren Stoutner <soren@stoutner.com>.
*
* This file is part of Privacy Browser <https://www.stoutner.com/privacy-browser>.
*
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
+import java.nio.charset.StandardCharsets;
import java.security.MessageDigest;
import java.security.SecureRandom;
import java.util.Arrays;
secureRandom.nextBytes(saltByteArray);
// Convert the encryption password to a byte array.
- byte[] encryptionPasswordByteArray = encryptionPasswordString.getBytes("UTF-8");
+ byte[] encryptionPasswordByteArray = encryptionPasswordString.getBytes(StandardCharsets.UTF_8);
// Append the salt to the encryption password byte array. This protects against rainbow table attacks.
byte[] encryptionPasswordWithSaltByteArray = new byte[encryptionPasswordByteArray.length + saltByteArray.length];
encryptedImportFileInputStream.read(initializationVector);
// Convert the encryption password to a byte array.
- byte[] encryptionPasswordByteArray = encryptionPasswordString.getBytes("UTF-8");
+ byte[] encryptionPasswordByteArray = encryptionPasswordString.getBytes(StandardCharsets.UTF_8);
// Append the salt to the encryption password byte array. This protects against rainbow table attacks.
byte[] encryptionPasswordWithSaltByteArray = new byte[encryptionPasswordByteArray.length + saltByteArray.length];
import android.net.Uri;
import android.net.http.SslCertificate;
import android.net.http.SslError;
+import android.os.AsyncTask;
import android.os.Build;
import android.os.Bundle;
import android.os.Environment;
import com.stoutner.privacybrowser.dialogs.EditBookmarkDialog;
import com.stoutner.privacybrowser.dialogs.EditBookmarkFolderDialog;
import com.stoutner.privacybrowser.dialogs.HttpAuthenticationDialog;
-import com.stoutner.privacybrowser.dialogs.PinnedSslCertificateMismatchDialog;
+import com.stoutner.privacybrowser.dialogs.PinnedMismatchDialog;
import com.stoutner.privacybrowser.dialogs.UrlHistoryDialog;
import com.stoutner.privacybrowser.dialogs.ViewSslCertificateDialog;
import com.stoutner.privacybrowser.helpers.AdHelper;
import java.io.File;
import java.io.IOException;
import java.io.UnsupportedEncodingException;
+import java.lang.ref.WeakReference;
+import java.net.InetAddress;
import java.net.MalformedURLException;
import java.net.URL;
import java.net.URLDecoder;
import java.net.URLEncoder;
+import java.net.UnknownHostException;
import java.util.ArrayList;
import java.util.Date;
import java.util.HashMap;
public class MainWebViewActivity extends AppCompatActivity implements CreateBookmarkDialog.CreateBookmarkListener, CreateBookmarkFolderDialog.CreateBookmarkFolderListener,
CreateHomeScreenShortcutDialog.CreateHomeScreenShortcutListener, DownloadFileDialog.DownloadFileListener, DownloadImageDialog.DownloadImageListener,
DownloadLocationPermissionDialog.DownloadLocationPermissionDialogListener, EditBookmarkDialog.EditBookmarkListener, EditBookmarkFolderDialog.EditBookmarkFolderListener,
- HttpAuthenticationDialog.HttpAuthenticationListener, NavigationView.OnNavigationItemSelectedListener, PinnedSslCertificateMismatchDialog.PinnedSslCertificateMismatchListener,
+ HttpAuthenticationDialog.HttpAuthenticationListener, NavigationView.OnNavigationItemSelectedListener, PinnedMismatchDialog.PinnedMismatchListener,
SslCertificateErrorDialog.SslCertificateErrorListener, UrlHistoryDialog.UrlHistoryListener {
// `darkTheme` is public static so it can be accessed from everywhere.
// `onCreateBookmark()`, `onCreateBookmarkFolder()`, `onCreateHomeScreenShortcutCreate()`, `onSaveEditBookmark()`, `onSaveEditBookmarkFolder()`, and `applyDomainSettings()`.
public static Bitmap favoriteIconBitmap;
- // `formattedUrlString` is public static so it can be accessed from `BookmarksActivity`, `CreateBookmarkDialog`, and `AddDomainDialog`.
+ // `favoriteIconDefaultBitmap` public static so it can be accessed from `PinnedMismatchDialog`. It is also used in `onCreate()` and `applyDomainSettings`.
+ public static Bitmap favoriteIconDefaultBitmap;
+
+ // `formattedUrlString` is public static so it can be accessed from `AddDomainDialog`, `BookmarksActivity`, `DomainSettingsFragment`, `CreateBookmarkDialog`, and `PinnedMismatchDialog`.
// It is also used in `onCreate()`, `onOptionsItemSelected()`, `onNavigationItemSelected()`, `onCreateHomeScreenShortcutCreate()`, `loadUrlFromTextBox()`, and `applyProxyThroughOrbot()`.
public static String formattedUrlString;
- // `sslCertificate` is public static so it can be accessed from `DomainsActivity`, `DomainsListFragment`, `DomainSettingsFragment`, `PinnedSslCertificateMismatchDialog`,
- // and `ViewSslCertificateDialog`. It is also used in `onCreate()`.
+ // `sslCertificate` is public static so it can be accessed from `DomainsActivity`, `DomainsListFragment`, `DomainSettingsFragment`, `PinnedMismatchDialog`, and `ViewSslCertificateDialog`.
+ // It is also used in `onCreate()`.
public static SslCertificate sslCertificate;
+ // `currentHostIpAddresses` is public static so it can be accessed from `DomainSettingsFragment` and `ViewSslCertificateDialog`.
+ // It is also used in `onCreate()` and `GetHostIpAddresses()`.
+ public static String currentHostIpAddresses;
+
// `orbotStatus` is public static so it can be accessed from `OrbotProxyHelper`. It is also used in `onCreate()`, `onResume()`, and `applyProxyThroughOrbot()`.
public static String orbotStatus;
// `onSaveEditBookmark()`, `onSaveEditBookmarkFolder()`, and `loadBookmarksFolder()`.
public static String currentBookmarksFolder;
- // `domainSettingsDatabaseId` is public static so it can be accessed from `PinnedSslCertificateMismatchDialog`. It is also used in `onCreate()`, `onOptionsItemSelected()`, and `applyDomainSettings()`.
+ // `domainSettingsDatabaseId` is public static so it can be accessed from `PinnedMismatchDialog`. It is also used in `onCreate()`, `onOptionsItemSelected()`, and `applyDomainSettings()`.
public static int domainSettingsDatabaseId;
- // The pinned domain SSL Certificate variables are public static so they can be accessed from `PinnedSslCertificateMismatchDialog`. They are also used in `onCreate()` and `applyDomainSettings()`.
- public static String pinnedDomainSslIssuedToCNameString;
- public static String pinnedDomainSslIssuedToONameString;
- public static String pinnedDomainSslIssuedToUNameString;
- public static String pinnedDomainSslIssuedByCNameString;
- public static String pinnedDomainSslIssuedByONameString;
- public static String pinnedDomainSslIssuedByUNameString;
- public static Date pinnedDomainSslStartDate;
- public static Date pinnedDomainSslEndDate;
+ // The pinned variables are public static so they can be accessed from `PinnedMismatchDialog`. They are also used in `onCreate()` and `applyDomainSettings()`.
+ public static String pinnedSslIssuedToCName;
+ public static String pinnedSslIssuedToOName;
+ public static String pinnedSslIssuedToUName;
+ public static String pinnedSslIssuedByCName;
+ public static String pinnedSslIssuedByOName;
+ public static String pinnedSslIssuedByUName;
+ public static Date pinnedSslStartDate;
+ public static Date pinnedSslEndDate;
+ public static String pinnedHostIpAddresses;
// The user agent constants are public static so they can be accessed from `SettingsFragment`, `DomainsActivity`, and `DomainSettingsFragment`.
public final static int UNRECOGNIZED_USER_AGENT = -1;
// `navigatingHistory` is used in `onCreate()`, `onNavigationItemSelected()`, `onSslMismatchBack()`, and `applyDomainSettings()`.
private boolean navigatingHistory;
- // `favoriteIconDefaultBitmap` is used in `onCreate()` and `applyDomainSettings`.
- private Bitmap favoriteIconDefaultBitmap;
-
// `drawerLayout` is used in `onCreate()`, `onNewIntent()`, `onBackPressed()`, and `onRestart()`.
private DrawerLayout drawerLayout;
// `currentDomainName` is used in `onCreate()`, `onOptionsItemSelected()`, `onNavigationItemSelected()`, `onAddDomain()`, and `applyDomainSettings()`.
private String currentDomainName;
- // `ignorePinnedSslCertificateForDomain` is used in `onCreate()`, `onSslMismatchProceed()`, and `applyDomainSettings()`.
- private boolean ignorePinnedSslCertificate;
+ // `pinnedDomainSslCertificate` is used in `onCreate()` and `applyDomainSettings()`.
+ private boolean pinnedSslCertificate;
+
+ // `pinnedIpAddress` is used in `onCreate()` and `applyDomainSettings()`.
+ private boolean pinnedIpAddresses;
+
+ // `ignorePinnedDomainInformation` is used in `onCreate()`, `onSslMismatchProceed()`, and `applyDomainSettings()`.
+ private boolean ignorePinnedDomainInformation;
// `orbotStatusBroadcastReceiver` is used in `onCreate()` and `onDestroy()`.
private BroadcastReceiver orbotStatusBroadcastReceiver;
// `urlIsLoading` is used in `onCreate()`, `onCreateOptionsMenu()`, `loadUrl()`, and `applyDomainSettings()`.
private boolean urlIsLoading;
- // `pinnedDomainSslCertificate` is used in `onCreate()` and `applyDomainSettings()`.
- private boolean pinnedDomainSslCertificate;
-
// `bookmarksDatabaseHelper` is used in `onCreate()`, `onDestroy`, `onOptionsItemSelected()`, `onCreateBookmark()`, `onCreateBookmarkFolder()`, `onSaveEditBookmark()`, `onSaveEditBookmarkFolder()`,
// and `loadBookmarksFolder()`.
private BookmarksDatabaseHelper bookmarksDatabaseHelper;
// Update the URL in urlTextBox when the page starts to load.
@Override
public void onPageStarted(WebView view, String url, Bitmap favicon) {
+ // Reset the list of host IP addresses.
+ currentHostIpAddresses = "";
+
// Reset the list of resource requests.
resourceRequests.clear();
// Apply text highlighting to `urlTextBox`.
highlightUrlText();
+ // Get a URI for the current URL.
+ Uri currentUri = Uri.parse(formattedUrlString);
+
+ // Get the IP addresses for the host.
+ new GetHostIpAddresses(activity).execute(currentUri.getHost());
+
// Apply any custom domain settings if the URL was loaded by navigating history.
if (navigatingHistory) {
// Apply the domain settings.
}
}
- // Update `urlTextBox` and apply domain settings if not waiting on Orbot.
+ // 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.
}
}
- // Store the SSL certificate so it can be accessed from `ViewSslCertificateDialog` and `PinnedSslCertificateMismatchDialog`.
+ // Store the SSL certificate so it can be accessed from `ViewSslCertificateDialog` and `PinnedMismatchDialog`.
sslCertificate = mainWebView.getCertificate();
- // Check the current website SSL certificate against the pinned SSL certificate if there is a pinned SSL certificate the user has not chosen to ignore it for this session.
- // Also ignore if changes in the user agent causes an error while navigating history.
- if (pinnedDomainSslCertificate && !ignorePinnedSslCertificate && navigatingHistory) {
+ // Check the current website information against any pinned domain information.
+ if ((pinnedSslCertificate || pinnedIpAddresses) && !ignorePinnedDomainInformation) {
// Initialize the current SSL certificate variables.
String currentWebsiteIssuedToCName = "";
String currentWebsiteIssuedToOName = "";
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`.
+ // 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 = "";
+ String pinnedSslStartDateString = "";
+ String pinnedSslEndDateString = "";
// Convert the `Dates` to `Strings` if they are not `null`.
if (currentWebsiteSslStartDate != null) {
currentWebsiteSslEndDateString = currentWebsiteSslEndDate.toString();
}
- if (pinnedDomainSslStartDate != null) {
- pinnedDomainSslStartDateString = pinnedDomainSslStartDate.toString();
+ if (pinnedSslStartDate != null) {
+ pinnedSslStartDateString = pinnedSslStartDate.toString();
}
- if (pinnedDomainSslEndDate != null) {
- pinnedDomainSslEndDateString = pinnedDomainSslEndDate.toString();
+ if (pinnedSslEndDate != null) {
+ pinnedSslEndDateString = pinnedSslEndDate.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));
+ // Check to see if the pinned information matches the current information.
+ if ((pinnedIpAddresses && !currentHostIpAddresses.equals(pinnedHostIpAddresses)) || (pinnedSslCertificate && (!currentWebsiteIssuedToCName.equals(pinnedSslIssuedToCName) ||
+ !currentWebsiteIssuedToOName.equals(pinnedSslIssuedToOName) || !currentWebsiteIssuedToUName.equals(pinnedSslIssuedToUName) ||
+ !currentWebsiteIssuedByCName.equals(pinnedSslIssuedByCName) || !currentWebsiteIssuedByOName.equals(pinnedSslIssuedByOName) ||
+ !currentWebsiteIssuedByUName.equals(pinnedSslIssuedByUName) || !currentWebsiteSslStartDateString.equals(pinnedSslStartDateString) ||
+ !currentWebsiteSslEndDateString.equals(pinnedSslEndDateString)))) {
+
+ // Get a handle for the pinned mismatch alert dialog.
+ AppCompatDialogFragment pinnedMismatchDialogFragment = PinnedMismatchDialog.displayDialog(pinnedSslCertificate, pinnedIpAddresses);
+
+ // Show the pinned mismatch alert dialog.
+ pinnedMismatchDialogFragment.show(getSupportFragmentManager(), getString(R.string.pinned_mismatch));
}
}
}
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.
+ if (pinnedSslCertificate &&
+ currentWebsiteIssuedToCName.equals(pinnedSslIssuedToCName) && currentWebsiteIssuedToOName.equals(pinnedSslIssuedToOName) &&
+ currentWebsiteIssuedToUName.equals(pinnedSslIssuedToUName) && currentWebsiteIssuedByCName.equals(pinnedSslIssuedByCName) &&
+ currentWebsiteIssuedByOName.equals(pinnedSslIssuedByOName) && currentWebsiteIssuedByUName.equals(pinnedSslIssuedByUName) &&
+ currentWebsiteSslStartDate.equals(pinnedSslStartDate) && currentWebsiteSslEndDate.equals(pinnedSslEndDate)) {
+
+ // 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()`.
mainWebView.reload();
return true;
- case R.id.print:
- // Get a `PrintManager` instance.
- PrintManager printManager = (PrintManager) getSystemService(Context.PRINT_SERVICE);
-
- // Convert `mainWebView` to `printDocumentAdapter`.
- PrintDocumentAdapter printDocumentAdapter = mainWebView.createPrintDocumentAdapter();
-
- // Remove the lint error below that `printManager` might be `null`.
- assert printManager != null;
-
- // Print the document. The print attributes are `null`.
- printManager.print(getString(R.string.privacy_browser_web_page), printDocumentAdapter, null);
- return true;
-
case R.id.find_on_page:
// Hide the URL app bar.
supportAppBar.setVisibility(View.GONE);
}, 200);
return true;
- case R.id.add_to_homescreen:
- // Show the alert dialog.
- AppCompatDialogFragment createHomeScreenShortcutDialogFragment = new CreateHomeScreenShortcutDialog();
- createHomeScreenShortcutDialogFragment.show(getSupportFragmentManager(), getString(R.string.create_shortcut));
-
- //Everything else will be handled by the alert dialog and the associated listener below.
- return true;
-
case R.id.view_source:
// Launch the View Source activity.
Intent viewSourceIntent = new Intent(this, ViewSourceActivity.class);
startActivity(Intent.createChooser(shareIntent, getString(R.string.share_url)));
return true;
+ case R.id.print:
+ // Get a `PrintManager` instance.
+ PrintManager printManager = (PrintManager) getSystemService(Context.PRINT_SERVICE);
+
+ // Convert `mainWebView` to `printDocumentAdapter`.
+ PrintDocumentAdapter printDocumentAdapter = mainWebView.createPrintDocumentAdapter();
+
+ // Remove the lint error below that `printManager` might be `null`.
+ assert printManager != null;
+
+ // Print the document. The print attributes are `null`.
+ printManager.print(getString(R.string.privacy_browser_web_page), printDocumentAdapter, null);
+ return true;
+
case R.id.open_with_app:
// Create the open with intent with `ACTION_VIEW`.
Intent openWithAppIntent = new Intent(Intent.ACTION_VIEW);
startActivity(Intent.createChooser(openWithBrowserIntent, getString(R.string.open_with)));
return true;
+ case R.id.add_to_homescreen:
+ // Show the alert dialog.
+ AppCompatDialogFragment createHomeScreenShortcutDialogFragment = new CreateHomeScreenShortcutDialog();
+ createHomeScreenShortcutDialogFragment.show(getSupportFragmentManager(), getString(R.string.create_shortcut));
+
+ //Everything else will be handled by the alert dialog and the associated listener below.
+ return true;
+
case R.id.proxy_through_orbot:
// Toggle the proxy through Orbot variable.
proxyThroughOrbot = !proxyThroughOrbot;
}
@Override
- public void onSslMismatchBack() {
+ public void onPinnedMismatchBack() {
if (mainWebView.canGoBack()) { // There is a back page in the history.
// Reset the formatted URL string so the page will load correctly if blocking of third-party requests is enabled.
formattedUrlString = "";
}
@Override
- public void onSslMismatchProceed() {
- // Do not check the pinned SSL certificate for this domain again until the domain changes.
- ignorePinnedSslCertificate = true;
+ public void onPinnedMismatchProceed() {
+ // Do not check the pinned information for this domain again until the domain changes.
+ ignorePinnedDomainInformation = true;
}
@Override
// Set the new `hostname` as the `currentDomainName`.
currentDomainName = hostName;
- // Reset `ignorePinnedSslCertificate`.
- ignorePinnedSslCertificate = false;
+ // Reset the ignoring of pinned domain information.
+ ignorePinnedDomainInformation = false;
// Reset the favorite icon if specified.
if (resetFavoriteIcon) {
int swipeToRefreshInt = currentHostDomainSettingsCursor.getInt(currentHostDomainSettingsCursor.getColumnIndex(DomainsDatabaseHelper.SWIPE_TO_REFRESH));
int nightModeInt = currentHostDomainSettingsCursor.getInt(currentHostDomainSettingsCursor.getColumnIndex(DomainsDatabaseHelper.NIGHT_MODE));
int displayWebpageImagesInt = currentHostDomainSettingsCursor.getInt(currentHostDomainSettingsCursor.getColumnIndex(DomainsDatabaseHelper.DISPLAY_IMAGES));
- pinnedDomainSslCertificate = (currentHostDomainSettingsCursor.getInt(currentHostDomainSettingsCursor.getColumnIndex(DomainsDatabaseHelper.PINNED_SSL_CERTIFICATE)) == 1);
- pinnedDomainSslIssuedToCNameString = currentHostDomainSettingsCursor.getString(currentHostDomainSettingsCursor.getColumnIndex(DomainsDatabaseHelper.SSL_ISSUED_TO_COMMON_NAME));
- pinnedDomainSslIssuedToONameString = currentHostDomainSettingsCursor.getString(currentHostDomainSettingsCursor.getColumnIndex(DomainsDatabaseHelper.SSL_ISSUED_TO_ORGANIZATION));
- pinnedDomainSslIssuedToUNameString = currentHostDomainSettingsCursor.getString(currentHostDomainSettingsCursor.getColumnIndex(DomainsDatabaseHelper.SSL_ISSUED_TO_ORGANIZATIONAL_UNIT));
- pinnedDomainSslIssuedByCNameString = currentHostDomainSettingsCursor.getString(currentHostDomainSettingsCursor.getColumnIndex(DomainsDatabaseHelper.SSL_ISSUED_BY_COMMON_NAME));
- pinnedDomainSslIssuedByONameString = currentHostDomainSettingsCursor.getString(currentHostDomainSettingsCursor.getColumnIndex(DomainsDatabaseHelper.SSL_ISSUED_BY_ORGANIZATION));
- pinnedDomainSslIssuedByUNameString = currentHostDomainSettingsCursor.getString(currentHostDomainSettingsCursor.getColumnIndex(DomainsDatabaseHelper.SSL_ISSUED_BY_ORGANIZATIONAL_UNIT));
+ pinnedSslCertificate = (currentHostDomainSettingsCursor.getInt(currentHostDomainSettingsCursor.getColumnIndex(DomainsDatabaseHelper.PINNED_SSL_CERTIFICATE)) == 1);
+ pinnedSslIssuedToCName = currentHostDomainSettingsCursor.getString(currentHostDomainSettingsCursor.getColumnIndex(DomainsDatabaseHelper.SSL_ISSUED_TO_COMMON_NAME));
+ pinnedSslIssuedToOName = currentHostDomainSettingsCursor.getString(currentHostDomainSettingsCursor.getColumnIndex(DomainsDatabaseHelper.SSL_ISSUED_TO_ORGANIZATION));
+ pinnedSslIssuedToUName = currentHostDomainSettingsCursor.getString(currentHostDomainSettingsCursor.getColumnIndex(DomainsDatabaseHelper.SSL_ISSUED_TO_ORGANIZATIONAL_UNIT));
+ pinnedSslIssuedByCName = currentHostDomainSettingsCursor.getString(currentHostDomainSettingsCursor.getColumnIndex(DomainsDatabaseHelper.SSL_ISSUED_BY_COMMON_NAME));
+ pinnedSslIssuedByOName = currentHostDomainSettingsCursor.getString(currentHostDomainSettingsCursor.getColumnIndex(DomainsDatabaseHelper.SSL_ISSUED_BY_ORGANIZATION));
+ pinnedSslIssuedByUName = currentHostDomainSettingsCursor.getString(currentHostDomainSettingsCursor.getColumnIndex(DomainsDatabaseHelper.SSL_ISSUED_BY_ORGANIZATIONAL_UNIT));
+ pinnedIpAddresses = (currentHostDomainSettingsCursor.getInt(currentHostDomainSettingsCursor.getColumnIndex(DomainsDatabaseHelper.PINNED_IP_ADDRESSES)) == 1);
+ pinnedHostIpAddresses = currentHostDomainSettingsCursor.getString(currentHostDomainSettingsCursor.getColumnIndex(DomainsDatabaseHelper.IP_ADDRESSES));
// Set `nightMode` according to `nightModeInt`. If `nightModeInt` is `DomainsDatabaseHelper.NIGHT_MODE_SYSTEM_DEFAULT` the current setting from `sharedPreferences` will be used.
switch (nightModeInt) {
// Set the pinned SSL certificate start date to `null` if the saved date `long` is 0.
if (currentHostDomainSettingsCursor.getLong(currentHostDomainSettingsCursor.getColumnIndex(DomainsDatabaseHelper.SSL_START_DATE)) == 0) {
- pinnedDomainSslStartDate = null;
+ pinnedSslStartDate = null;
} else {
- pinnedDomainSslStartDate = new Date(currentHostDomainSettingsCursor.getLong(currentHostDomainSettingsCursor.getColumnIndex(DomainsDatabaseHelper.SSL_START_DATE)));
+ pinnedSslStartDate = new Date(currentHostDomainSettingsCursor.getLong(currentHostDomainSettingsCursor.getColumnIndex(DomainsDatabaseHelper.SSL_START_DATE)));
}
// Set the pinned SSL certificate end date to `null` if the saved date `long` is 0.
if (currentHostDomainSettingsCursor.getLong(currentHostDomainSettingsCursor.getColumnIndex(DomainsDatabaseHelper.SSL_END_DATE)) == 0) {
- pinnedDomainSslEndDate = null;
+ pinnedSslEndDate = null;
} else {
- pinnedDomainSslEndDate = new Date(currentHostDomainSettingsCursor.getLong(currentHostDomainSettingsCursor.getColumnIndex(DomainsDatabaseHelper.SSL_END_DATE)));
+ pinnedSslEndDate = new Date(currentHostDomainSettingsCursor.getLong(currentHostDomainSettingsCursor.getColumnIndex(DomainsDatabaseHelper.SSL_END_DATE)));
}
// Close `currentHostDomainSettingsCursor`.
mainWebView.getSettings().setSaveFormData(saveFormDataEnabled);
}
- // Reset the pinned SSL certificate information.
+ // Reset the pinned variables.
domainSettingsDatabaseId = -1;
- pinnedDomainSslCertificate = false;
- pinnedDomainSslIssuedToCNameString = "";
- pinnedDomainSslIssuedToONameString = "";
- pinnedDomainSslIssuedToUNameString = "";
- pinnedDomainSslIssuedByCNameString = "";
- pinnedDomainSslIssuedByONameString = "";
- pinnedDomainSslIssuedByUNameString = "";
- pinnedDomainSslStartDate = null;
- pinnedDomainSslEndDate = null;
+ pinnedSslCertificate = false;
+ pinnedSslIssuedToCName = "";
+ pinnedSslIssuedToOName = "";
+ pinnedSslIssuedToUName = "";
+ pinnedSslIssuedByCName = "";
+ pinnedSslIssuedByOName = "";
+ pinnedSslIssuedByUName = "";
+ pinnedSslStartDate = null;
+ pinnedSslEndDate = null;
+ pinnedIpAddresses = false;
+ pinnedHostIpAddresses = "";
// Set third-party cookies status if API >= 21.
if (Build.VERSION.SDK_INT >= 21) {
bookmarksTitleTextView.setText(currentBookmarksFolder);
}
}
+
+ // This must run asynchronously because it involves a network request. `String` declares the parameters. `Void` does not declare progress units. `String` contains the results.
+ private static class GetHostIpAddresses extends AsyncTask<String, Void, String> {
+ // The weak references are used to determine if the activity have disappeared while the AsyncTask is running.
+ private final WeakReference<Activity> activityWeakReference;
+
+ GetHostIpAddresses(Activity activity) {
+ // Populate the weak references.
+ activityWeakReference = new WeakReference<>(activity);
+ }
+
+ @Override
+ protected String doInBackground(String... domainName) {
+ // Get handles for the activity and the alert dialog.
+ Activity activity = activityWeakReference.get();
+
+ // Abort if the activity or the dialog is gone.
+ if ((activity == null) || activity.isFinishing()) {
+ // Return an empty spannable string builder.
+ return "";
+ }
+
+ // Initialize an IP address string builder.
+ StringBuilder ipAddresses = new StringBuilder();
+
+ // Get an array with the IP addresses for the host.
+ try {
+ // Get an array with all the IP addresses for the domain.
+ InetAddress[] inetAddressesArray = InetAddress.getAllByName(domainName[0]);
+
+ // Add each IP address to the string builder.
+ for (InetAddress inetAddress : inetAddressesArray) {
+ if (ipAddresses.length() == 0) { // This is the first IP address.
+ // Add the IP address to the string builder.
+ ipAddresses.append(inetAddress.getHostAddress());
+ } else { // This is not the first IP address.
+ // Add a line break to the string builder first.
+ ipAddresses.append("\n");
+
+ // Add the IP address to the string builder.
+ ipAddresses.append(inetAddress.getHostAddress());
+ }
+ }
+ } catch (UnknownHostException exception) {
+ // Do nothing.
+ }
+
+ // Return the string.
+ return ipAddresses.toString();
+ }
+
+ // `onPostExecute()` operates on the UI thread.
+ @Override
+ protected void onPostExecute(String ipAddresses) {
+ // Get handles for the activity and the alert dialog.
+ Activity activity = activityWeakReference.get();
+
+ // Abort if the activity or the alert dialog is gone.
+ if ((activity == null) || activity.isFinishing()) {
+ return;
+ }
+
+ // Store the IP addresses.
+ currentHostIpAddresses = ipAddresses;
+ }
+ }
}
\ No newline at end of file
/*
- * 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>.
*
Activity viewSourceActivity = activityWeakReference.get();
// Abort if the activity is gone.
- if ((viewSourceActivity == null) || (viewSourceActivity.isFinishing())) {
+ if ((viewSourceActivity == null) || viewSourceActivity.isFinishing()) {
return;
}
Activity activity = activityWeakReference.get();
// Abort if the activity is gone.
- if ((activity == null) || (activity.isFinishing())) {
+ if ((activity == null) || activity.isFinishing()) {
return new SpannableStringBuilder[] {requestHeadersBuilder, responseMessageBuilder, responseHeadersBuilder, responseBodyBuilder};
}
Activity activity = activityWeakReference.get();
// Abort if the activity is gone.
- if ((activity == null) || (activity.isFinishing())) {
+ if ((activity == null) || activity.isFinishing()) {
return;
}
/*
- * Copyright © 2016-2018 Soren Stoutner <soren@stoutner.com>.
+ * Copyright © 2016-2019 Soren Stoutner <soren@stoutner.com>.
*
* This file is part of Privacy Browser <https://www.stoutner.com/privacy-browser>.
*
// Create a variable for the file name string.
String fileNameString;
- // Parse `filename` from `contentDisposition`.
+ // Parse the filename from `contentDisposition`.
if (contentDisposition.contains("filename=\"")) { // The file name is contained in a string surrounded by `""`.
fileNameString = contentDisposition.substring(contentDisposition.indexOf("filename=\"") + 10, contentDisposition.indexOf("\"", contentDisposition.indexOf("filename=\"") + 10));
- } else if (contentDisposition.contains("filename=") && ((contentDisposition.indexOf(";", contentDisposition.indexOf("filename=") + 9)) > 0 )) { // The file name is contained in a string beginning with `filename=` and ending with `;`.
+ } else if (contentDisposition.contains("filename=") && ((contentDisposition.indexOf(";", contentDisposition.indexOf("filename=") + 9)) > 0 )) {
+ // The file name is contained in a string beginning with `filename=` and ending with `;`.
fileNameString = contentDisposition.substring(contentDisposition.indexOf("filename=") + 9, contentDisposition.indexOf(";", contentDisposition.indexOf("filename=") + 9));
} else if (contentDisposition.contains("filename=")) { // The file name is contained in a string beginning with `filename=` and proceeding to the end of `contentDisposition`.
- fileNameString = contentDisposition.substring(contentDisposition.indexOf("filename=") + 9, contentDisposition.length());
+ fileNameString = contentDisposition.substring(contentDisposition.indexOf("filename=") + 9);
} else { // `contentDisposition` does not contain the filename, so use the last path segment of the URL.
Uri downloadUri = Uri.parse(urlString);
fileNameString = downloadUri.getLastPathSegment();
--- /dev/null
+/*
+ * Copyright © 2017-2019 Soren Stoutner <soren@stoutner.com>.
+ *
+ * This file is part of Privacy Browser <https://www.stoutner.com/privacy-browser>.
+ *
+ * Privacy Browser is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * Privacy Browser is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Privacy Browser. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+package com.stoutner.privacybrowser.dialogs;
+
+import android.annotation.SuppressLint;
+import android.app.AlertDialog;
+import android.app.Dialog;
+import android.content.Context;
+import android.content.DialogInterface;
+import android.graphics.drawable.BitmapDrawable;
+import android.graphics.drawable.Drawable;
+import android.net.Uri;
+import android.net.http.SslCertificate;
+import android.os.Bundle;
+import android.support.annotation.NonNull;
+import android.support.design.widget.TabLayout;
+import android.support.v4.view.PagerAdapter;
+// `AppCompatDialogFragment` is used instead of `DialogFragment` to avoid an error on API <=22.
+import android.support.v7.app.AppCompatDialogFragment;
+import android.text.SpannableStringBuilder;
+import android.text.Spanned;
+import android.text.style.ForegroundColorSpan;
+import android.view.LayoutInflater;
+import android.view.View;
+import android.view.ViewGroup;
+import android.view.WindowManager;
+import android.widget.TextView;
+
+import com.stoutner.privacybrowser.R;
+import com.stoutner.privacybrowser.activities.MainWebViewActivity;
+import com.stoutner.privacybrowser.definitions.WrapVerticalContentViewPager;
+import com.stoutner.privacybrowser.helpers.DomainsDatabaseHelper;
+
+import java.text.DateFormat;
+import java.util.Date;
+
+public class PinnedMismatchDialog extends AppCompatDialogFragment {
+ // Instantiate the class variables.
+ private PinnedMismatchListener pinnedMismatchListener;
+ private LayoutInflater layoutInflater;
+ private String currentSslIssuedToCName;
+ private String currentSslIssuedToOName;
+ private String currentSslIssuedToUName;
+ private String currentSslIssuedByCName;
+ private String currentSslIssuedByOName;
+ private String currentSslIssuedByUName;
+ private Date currentSslStartDate;
+ private Date currentSslEndDate;
+ private boolean pinnedSslCertificate;
+ private boolean pinnedIpAddresses;
+
+ // The public interface is used to send information back to the parent activity.
+ public interface PinnedMismatchListener {
+ void onPinnedMismatchBack();
+
+ void onPinnedMismatchProceed();
+ }
+
+ // Check to make sure that the parent activity implements the listener.
+ public void onAttach(Context context) {
+ // Run the default commands.
+ super.onAttach(context);
+
+ // Get a handle for `PinnedSslCertificateMismatchListener` from the launching context.
+ pinnedMismatchListener = (PinnedMismatchListener) context;
+ }
+
+ public static PinnedMismatchDialog displayDialog(boolean pinnedSslCertificate, boolean pinnedIpAddresses) {
+ // Create an arguments bundle.
+ Bundle argumentsBundle = new Bundle();
+
+ // Store the variables in the bundle.
+ argumentsBundle.putBoolean("Pinned_SSL_Certificate", pinnedSslCertificate);
+ argumentsBundle.putBoolean("Pinned_IP_Addresses", pinnedIpAddresses);
+
+ // Add the arguments bundle to this instance of `PinnedMismatchDialog`.
+ PinnedMismatchDialog thisPinnedMismatchDialog = new PinnedMismatchDialog();
+ thisPinnedMismatchDialog.setArguments(argumentsBundle);
+ return thisPinnedMismatchDialog;
+ }
+
+ // `@SuppressLing("InflateParams")` removes the warning about using `null` as the parent view group when inflating the `AlertDialog`.
+ @SuppressLint("InflateParams")
+ @Override
+ @NonNull
+ public Dialog onCreateDialog(Bundle savedInstanceState) {
+ // Remove the incorrect lint warning that `getActivity()` might be null.
+ assert getActivity() != null;
+
+ // Get the activity's layout inflater.
+ layoutInflater = getActivity().getLayoutInflater();
+
+ // Use an alert dialog builder to create the alert dialog.
+ AlertDialog.Builder dialogBuilder;
+
+ // Set the style according to the theme.
+ if (MainWebViewActivity.darkTheme) {
+ // Set the dialog theme.
+ dialogBuilder = new AlertDialog.Builder(getActivity(), R.style.PrivacyBrowserAlertDialogDark);
+ } else {
+ // Set the dialog theme.
+ dialogBuilder = new AlertDialog.Builder(getActivity(), R.style.PrivacyBrowserAlertDialogLight);
+ }
+
+ // Remove the incorrect lint warning below that `.getArguments.getBoolean()` might be null.
+ assert getArguments() != null;
+
+ // Get the variables from the bundle.
+ pinnedSslCertificate = getArguments().getBoolean("Pinned_SSL_Certificate");
+ pinnedIpAddresses = getArguments().getBoolean("Pinned_IP_Addresses");
+
+ if (MainWebViewActivity.favoriteIconBitmap.equals(MainWebViewActivity.favoriteIconDefaultBitmap)) {
+ // Set the icon according to the theme.
+ if (MainWebViewActivity.darkTheme) {
+ dialogBuilder.setIcon(R.drawable.ssl_certificate_enabled_dark);
+ } else {
+ dialogBuilder.setIcon(R.drawable.ssl_certificate_enabled_light);
+ }
+ } else {
+ // Create a drawable version of the favorite icon.
+ Drawable favoriteIconDrawable = new BitmapDrawable(getResources(), MainWebViewActivity.favoriteIconBitmap);
+
+ // Set the icon.
+ dialogBuilder.setIcon(favoriteIconDrawable);
+ }
+
+ // Setup the neutral button.
+ dialogBuilder.setNeutralButton(R.string.update, (DialogInterface dialog, int which) -> {
+ // Initialize the long date variables. If the date is null, a long value of `0` will be stored in the Domains database entry.
+ long currentSslStartDateLong = 0;
+ long currentSslEndDateLong = 0;
+
+ // Convert the `Dates` into `longs`.
+ if (currentSslStartDate != null) {
+ currentSslStartDateLong = currentSslStartDate.getTime();
+ }
+
+ if (currentSslEndDate != null) {
+ currentSslEndDateLong = currentSslEndDate.getTime();
+ }
+
+ // Initialize the database handler. The `0` specifies the database version, but that is ignored and set instead using a constant in `DomainsDatabaseHelper`.
+ DomainsDatabaseHelper domainsDatabaseHelper = new DomainsDatabaseHelper(getContext(), null, null, 0);
+
+ // Update the SSL certificate if it is pinned.
+ if (pinnedSslCertificate) {
+ // Update the pinned SSL certificate in the domain database.
+ domainsDatabaseHelper.updatePinnedSslCertificate(MainWebViewActivity.domainSettingsDatabaseId, currentSslIssuedToCName, currentSslIssuedToOName, currentSslIssuedToUName,
+ currentSslIssuedByCName, currentSslIssuedByOName, currentSslIssuedByUName, currentSslStartDateLong, currentSslEndDateLong);
+
+ // Update the pinned SSL certificate class variables to match the information that is now in the database.
+ MainWebViewActivity.pinnedSslIssuedToCName = currentSslIssuedToCName;
+ MainWebViewActivity.pinnedSslIssuedToOName = currentSslIssuedToOName;
+ MainWebViewActivity.pinnedSslIssuedToUName = currentSslIssuedToUName;
+ MainWebViewActivity.pinnedSslIssuedByCName = currentSslIssuedByCName;
+ MainWebViewActivity.pinnedSslIssuedByOName = currentSslIssuedByOName;
+ MainWebViewActivity.pinnedSslIssuedByUName = currentSslIssuedByUName;
+ MainWebViewActivity.pinnedSslStartDate = currentSslStartDate;
+ MainWebViewActivity.pinnedSslEndDate = currentSslEndDate;
+ }
+
+ // Update the IP addresses if they are pinned.
+ if (pinnedIpAddresses) {
+ // Update the pinned IP addresses in the domain database.
+ domainsDatabaseHelper.updatePinnedIpAddresses(MainWebViewActivity.domainSettingsDatabaseId, MainWebViewActivity.currentHostIpAddresses);
+
+ // Update the pinned IP addresses class variable to match the information that is now in the database.
+ MainWebViewActivity.pinnedHostIpAddresses = MainWebViewActivity.currentHostIpAddresses;
+ }
+ });
+
+ // Setup the negative button.
+ dialogBuilder.setNegativeButton(R.string.back, (DialogInterface dialog, int which) -> {
+ // Call the `onSslMismatchBack` public interface to send the `WebView` back one page.
+ pinnedMismatchListener.onPinnedMismatchBack();
+ });
+
+ // Setup the positive button.
+ dialogBuilder.setPositiveButton(R.string.proceed, (DialogInterface dialog, int which) -> {
+ // Call the `onSslMismatchProceed` public interface.
+ pinnedMismatchListener.onPinnedMismatchProceed();
+ });
+
+ // Set the title.
+ dialogBuilder.setTitle(R.string.pinned_mismatch);
+
+ // Set the layout. The parent view is `null` because it will be assigned by `AlertDialog`.
+ dialogBuilder.setView(layoutInflater.inflate(R.layout.pinned_mismatch_linearlayout, null));
+
+ // Create an alert dialog from the alert dialog builder.
+ final AlertDialog alertDialog = dialogBuilder.create();
+
+ // Disable screenshots if not allowed.
+ if (!MainWebViewActivity.allowScreenshots) {
+ // Remove the warning below that `getWindow()` might be null.
+ assert alertDialog.getWindow() != null;
+
+ // Disable screenshots.
+ alertDialog.getWindow().addFlags(WindowManager.LayoutParams.FLAG_SECURE);
+ }
+
+ // Show the alert dialog so the items in the layout can be modified.
+ alertDialog.show();
+
+ // Setup the view pager.
+ WrapVerticalContentViewPager wrapVerticalContentViewPager = alertDialog.findViewById(R.id.pinned_ssl_certificate_mismatch_viewpager);
+ wrapVerticalContentViewPager.setAdapter(new pagerAdapter());
+
+ // Setup the tab layout and connect it to the view pager.
+ TabLayout tabLayout = alertDialog.findViewById(R.id.pinned_ssl_certificate_mismatch_tablayout);
+ tabLayout.setupWithViewPager(wrapVerticalContentViewPager);
+
+ // `onCreateDialog()` requires the return of an `AlertDialog`.
+ return alertDialog;
+ }
+
+ private class pagerAdapter extends PagerAdapter {
+ @Override
+ public boolean isViewFromObject(@NonNull View view, @NonNull Object object) {
+ // Check to see if the `View` and the `Object` are the same.
+ return (view == object);
+ }
+
+ @Override
+ public int getCount() {
+ // There are two tabs.
+ return 2;
+ }
+
+ @Override
+ public CharSequence getPageTitle(int position) {
+ // Return the current tab title.
+ if (position == 0) { // The current SSL certificate tab.
+ return getString(R.string.current);
+ } else { // The pinned SSL certificate tab.
+ return getString(R.string.pinned);
+ }
+ }
+
+ @Override
+ @NonNull
+ public Object instantiateItem(@NonNull ViewGroup container, int position) {
+ // Inflate the scroll view for this tab.
+ ViewGroup tabViewGroup = (ViewGroup) layoutInflater.inflate(R.layout.pinned_mismatch_scrollview, container, false);
+
+ // Get handles for the `TextViews`.
+ TextView domainNameTextView = tabViewGroup.findViewById(R.id.domain_name);
+ TextView ipAddressesTextView = tabViewGroup.findViewById(R.id.ip_addresses);
+ TextView issuedToCNameTextView = tabViewGroup.findViewById(R.id.issued_to_cname);
+ TextView issuedToONameTextView = tabViewGroup.findViewById(R.id.issued_to_oname);
+ TextView issuedToUNameTextView = tabViewGroup.findViewById(R.id.issued_to_uname);
+ TextView issuedByCNameTextView = tabViewGroup.findViewById(R.id.issued_by_cname);
+ TextView issuedByONameTextView = tabViewGroup.findViewById(R.id.issued_by_oname);
+ TextView issuedByUNameTextView = tabViewGroup.findViewById(R.id.issued_by_uname);
+ TextView startDateTextView = tabViewGroup.findViewById(R.id.start_date);
+ TextView endDateTextView = tabViewGroup.findViewById(R.id.end_date);
+
+ // Setup the labels.
+ String domainNameLabel = getString(R.string.domain_label) + " ";
+ String ipAddressesLabel = getString(R.string.ip_addresses) + " ";
+ String cNameLabel = getString(R.string.common_name) + " ";
+ String oNameLabel = getString(R.string.organization) + " ";
+ String uNameLabel = getString(R.string.organizational_unit) + " ";
+ String startDateLabel = getString(R.string.start_date) + " ";
+ String endDateLabel = getString(R.string.end_date) + " ";
+
+ // Get a URI for the URL.
+ Uri currentUri = Uri.parse(MainWebViewActivity.formattedUrlString);
+
+ // Get the current host from the URI.
+ String domainName = currentUri.getHost();
+
+ // Get the current website SSL certificate.
+ SslCertificate sslCertificate = MainWebViewActivity.sslCertificate;
+
+ // Extract the individual pieces of information from the current website SSL certificate if it is not null.
+ if (sslCertificate != null) {
+ currentSslIssuedToCName = sslCertificate.getIssuedTo().getCName();
+ currentSslIssuedToOName = sslCertificate.getIssuedTo().getOName();
+ currentSslIssuedToUName = sslCertificate.getIssuedTo().getUName();
+ currentSslIssuedByCName = sslCertificate.getIssuedBy().getCName();
+ currentSslIssuedByOName = sslCertificate.getIssuedBy().getOName();
+ currentSslIssuedByUName = sslCertificate.getIssuedBy().getUName();
+ currentSslStartDate = sslCertificate.getValidNotBeforeDate();
+ currentSslEndDate = sslCertificate.getValidNotAfterDate();
+ } else {
+ // Initialize the current website SSL certificate variables with blank information.
+ currentSslIssuedToCName = "";
+ currentSslIssuedToOName = "";
+ currentSslIssuedToUName = "";
+ currentSslIssuedByCName = "";
+ currentSslIssuedByOName = "";
+ currentSslIssuedByUName = "";
+ }
+
+ // Setup the domain name spannable string builder.
+ SpannableStringBuilder domainNameStringBuilder = new SpannableStringBuilder(domainNameLabel + domainName);
+
+ // Initialize the spannable string builders.
+ SpannableStringBuilder ipAddressesStringBuilder;
+ SpannableStringBuilder issuedToCNameStringBuilder;
+ SpannableStringBuilder issuedToONameStringBuilder;
+ SpannableStringBuilder issuedToUNameStringBuilder;
+ SpannableStringBuilder issuedByCNameStringBuilder;
+ SpannableStringBuilder issuedByONameStringBuilder;
+ SpannableStringBuilder issuedByUNameStringBuilder;
+ SpannableStringBuilder startDateStringBuilder;
+ SpannableStringBuilder endDateStringBuilder;
+
+ // Setup the spannable string builders for each tab.
+ if (position == 0) { // Setup the current settings tab.
+ // Create the string builders.
+ ipAddressesStringBuilder = new SpannableStringBuilder(ipAddressesLabel + MainWebViewActivity.currentHostIpAddresses);
+ issuedToCNameStringBuilder = new SpannableStringBuilder(cNameLabel + currentSslIssuedToCName);
+ issuedToONameStringBuilder = new SpannableStringBuilder(oNameLabel + currentSslIssuedToOName);
+ issuedToUNameStringBuilder = new SpannableStringBuilder(uNameLabel + currentSslIssuedToUName);
+ issuedByCNameStringBuilder = new SpannableStringBuilder(cNameLabel + currentSslIssuedByCName);
+ issuedByONameStringBuilder = new SpannableStringBuilder(oNameLabel + currentSslIssuedByOName);
+ issuedByUNameStringBuilder = new SpannableStringBuilder(uNameLabel + currentSslIssuedByUName);
+
+ // Set the dates if they aren't `null`.
+ if (currentSslStartDate == null) {
+ startDateStringBuilder = new SpannableStringBuilder(startDateLabel);
+ } else {
+ startDateStringBuilder = new SpannableStringBuilder(startDateLabel + DateFormat.getDateTimeInstance(DateFormat.MEDIUM, DateFormat.LONG).format(currentSslStartDate));
+ }
+
+ if (currentSslEndDate == null) {
+ endDateStringBuilder = new SpannableStringBuilder(endDateLabel);
+ } else {
+ endDateStringBuilder = new SpannableStringBuilder(endDateLabel + DateFormat.getDateTimeInstance(DateFormat.MEDIUM, DateFormat.LONG).format(currentSslEndDate));
+ }
+ } else { // Setup the pinned settings tab.
+ // Create the string builders.
+ ipAddressesStringBuilder = new SpannableStringBuilder(ipAddressesLabel + MainWebViewActivity.pinnedHostIpAddresses);
+ issuedToCNameStringBuilder = new SpannableStringBuilder(cNameLabel + MainWebViewActivity.pinnedSslIssuedToCName);
+ issuedToONameStringBuilder = new SpannableStringBuilder(oNameLabel + MainWebViewActivity.pinnedSslIssuedToOName);
+ issuedToUNameStringBuilder = new SpannableStringBuilder(uNameLabel + MainWebViewActivity.pinnedSslIssuedToUName);
+ issuedByCNameStringBuilder = new SpannableStringBuilder(cNameLabel + MainWebViewActivity.pinnedSslIssuedByCName);
+ issuedByONameStringBuilder = new SpannableStringBuilder(oNameLabel + MainWebViewActivity.pinnedSslIssuedByOName);
+ issuedByUNameStringBuilder = new SpannableStringBuilder(uNameLabel + MainWebViewActivity.pinnedSslIssuedByUName);
+
+ // Set the dates if they aren't `null`.
+ if (MainWebViewActivity.pinnedSslStartDate == null) {
+ startDateStringBuilder = new SpannableStringBuilder(startDateLabel);
+ } else {
+ startDateStringBuilder = new SpannableStringBuilder(startDateLabel + DateFormat.getDateTimeInstance(DateFormat.MEDIUM, DateFormat.LONG)
+ .format(MainWebViewActivity.pinnedSslStartDate));
+ }
+
+ if (MainWebViewActivity.pinnedSslEndDate == null) {
+ endDateStringBuilder = new SpannableStringBuilder(endDateLabel);
+ } else {
+ endDateStringBuilder = new SpannableStringBuilder(endDateLabel + DateFormat.getDateTimeInstance(DateFormat.MEDIUM, DateFormat.LONG).format(MainWebViewActivity.pinnedSslEndDate));
+ }
+ }
+
+ // Create a red foreground color span. The deprecated `getResources().getColor` must be used until the minimum API >= 23.
+ @SuppressWarnings("deprecation") ForegroundColorSpan redColorSpan = new ForegroundColorSpan(getResources().getColor(R.color.red_a700));
+
+ // Create a blue foreground color span.
+ ForegroundColorSpan blueColorSpan;
+
+ // Set the blue color span according to the theme. The deprecated `getResources().getColor` must be used until the minimum API >= 23.
+ if (MainWebViewActivity.darkTheme) {
+ //noinspection deprecation
+ blueColorSpan = new ForegroundColorSpan(getResources().getColor(R.color.blue_400));
+ } else {
+ //noinspection deprecation
+ blueColorSpan = new ForegroundColorSpan(getResources().getColor(R.color.blue_700));
+ }
+
+ // Set the domain name to be blue.
+ domainNameStringBuilder.setSpan(blueColorSpan, domainNameLabel.length(), domainNameStringBuilder.length(), Spanned.SPAN_INCLUSIVE_INCLUSIVE);
+
+ // Color coordinate the IP addresses if they are pinned.
+ if (pinnedIpAddresses) {
+ if (MainWebViewActivity.currentHostIpAddresses.equals(MainWebViewActivity.pinnedHostIpAddresses)) {
+ ipAddressesStringBuilder.setSpan(blueColorSpan, ipAddressesLabel.length(), ipAddressesStringBuilder.length(), Spanned.SPAN_INCLUSIVE_INCLUSIVE);
+ } else {
+ ipAddressesStringBuilder.setSpan(redColorSpan, ipAddressesLabel.length(), ipAddressesStringBuilder.length(), Spanned.SPAN_INCLUSIVE_INCLUSIVE);
+ }
+ }
+
+ // Color coordinate the SSL certificate fields if they are pinned.
+ if (pinnedSslCertificate) {
+ if (currentSslIssuedToCName.equals(MainWebViewActivity.pinnedSslIssuedToCName)) {
+ issuedToCNameStringBuilder.setSpan(blueColorSpan, cNameLabel.length(), issuedToCNameStringBuilder.length(), Spanned.SPAN_INCLUSIVE_INCLUSIVE);
+ } else {
+ issuedToCNameStringBuilder.setSpan(redColorSpan, cNameLabel.length(), issuedToCNameStringBuilder.length(), Spanned.SPAN_INCLUSIVE_INCLUSIVE);
+ }
+
+ if (currentSslIssuedToOName.equals(MainWebViewActivity.pinnedSslIssuedToOName)) {
+ issuedToONameStringBuilder.setSpan(blueColorSpan, oNameLabel.length(), issuedToONameStringBuilder.length(), Spanned.SPAN_INCLUSIVE_INCLUSIVE);
+ } else {
+ issuedToONameStringBuilder.setSpan(redColorSpan, oNameLabel.length(), issuedToONameStringBuilder.length(), Spanned.SPAN_INCLUSIVE_INCLUSIVE);
+ }
+
+ if (currentSslIssuedToUName.equals(MainWebViewActivity.pinnedSslIssuedToUName)) {
+ issuedToUNameStringBuilder.setSpan(blueColorSpan, uNameLabel.length(), issuedToUNameStringBuilder.length(), Spanned.SPAN_INCLUSIVE_INCLUSIVE);
+ } else {
+ issuedToUNameStringBuilder.setSpan(redColorSpan, uNameLabel.length(), issuedToUNameStringBuilder.length(), Spanned.SPAN_INCLUSIVE_INCLUSIVE);
+ }
+
+ if (currentSslIssuedByCName.equals(MainWebViewActivity.pinnedSslIssuedByCName)) {
+ issuedByCNameStringBuilder.setSpan(blueColorSpan, cNameLabel.length(), issuedByCNameStringBuilder.length(), Spanned.SPAN_INCLUSIVE_INCLUSIVE);
+ } else {
+ issuedByCNameStringBuilder.setSpan(redColorSpan, cNameLabel.length(), issuedByCNameStringBuilder.length(), Spanned.SPAN_INCLUSIVE_INCLUSIVE);
+ }
+
+ if (currentSslIssuedByOName.equals(MainWebViewActivity.pinnedSslIssuedByOName)) {
+ issuedByONameStringBuilder.setSpan(blueColorSpan, oNameLabel.length(), issuedByONameStringBuilder.length(), Spanned.SPAN_INCLUSIVE_INCLUSIVE);
+ } else {
+ issuedByONameStringBuilder.setSpan(redColorSpan, oNameLabel.length(), issuedByONameStringBuilder.length(), Spanned.SPAN_INCLUSIVE_INCLUSIVE);
+ }
+
+ if (currentSslIssuedByUName.equals(MainWebViewActivity.pinnedSslIssuedByUName)) {
+ issuedByUNameStringBuilder.setSpan(blueColorSpan, uNameLabel.length(), issuedByUNameStringBuilder.length(), Spanned.SPAN_INCLUSIVE_INCLUSIVE);
+ } else {
+ issuedByUNameStringBuilder.setSpan(redColorSpan, uNameLabel.length(), issuedByUNameStringBuilder.length(), Spanned.SPAN_INCLUSIVE_INCLUSIVE);
+ }
+
+ if ((currentSslStartDate != null) && currentSslStartDate.equals(MainWebViewActivity.pinnedSslStartDate)) {
+ startDateStringBuilder.setSpan(blueColorSpan, startDateLabel.length(), startDateStringBuilder.length(), Spanned.SPAN_INCLUSIVE_INCLUSIVE);
+ } else {
+ startDateStringBuilder.setSpan(redColorSpan, startDateLabel.length(), startDateStringBuilder.length(), Spanned.SPAN_INCLUSIVE_INCLUSIVE);
+ }
+
+ if ((currentSslEndDate != null) && currentSslEndDate.equals(MainWebViewActivity.pinnedSslEndDate)) {
+ endDateStringBuilder.setSpan(blueColorSpan, endDateLabel.length(), endDateStringBuilder.length(), Spanned.SPAN_INCLUSIVE_INCLUSIVE);
+ } else {
+ endDateStringBuilder.setSpan(redColorSpan, endDateLabel.length(), endDateStringBuilder.length(), Spanned.SPAN_INCLUSIVE_INCLUSIVE);
+ }
+ }
+
+ // Display the strings.
+ domainNameTextView.setText(domainNameStringBuilder);
+ ipAddressesTextView.setText(ipAddressesStringBuilder);
+ issuedToCNameTextView.setText(issuedToCNameStringBuilder);
+ issuedToONameTextView.setText(issuedToONameStringBuilder);
+ issuedToUNameTextView.setText(issuedToUNameStringBuilder);
+ issuedByCNameTextView.setText(issuedByCNameStringBuilder);
+ issuedByONameTextView.setText(issuedByONameStringBuilder);
+ issuedByUNameTextView.setText(issuedByUNameStringBuilder);
+ startDateTextView.setText(startDateStringBuilder);
+ endDateTextView.setText(endDateStringBuilder);
+
+ // Display the tab.
+ container.addView(tabViewGroup);
+
+ // Make it so.
+ return tabViewGroup;
+ }
+ }
+}
+++ /dev/null
-/*
- * Copyright © 2017-2018 Soren Stoutner <soren@stoutner.com>.
- *
- * This file is part of Privacy Browser <https://www.stoutner.com/privacy-browser>.
- *
- * Privacy Browser is free software: you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation, either version 3 of the License, or
- * (at your option) any later version.
- *
- * Privacy Browser is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with Privacy Browser. If not, see <http://www.gnu.org/licenses/>.
- */
-
-package com.stoutner.privacybrowser.dialogs;
-
-import android.annotation.SuppressLint;
-import android.app.AlertDialog;
-import android.app.Dialog;
-import android.content.Context;
-import android.content.DialogInterface;
-import android.net.http.SslCertificate;
-import android.os.Bundle;
-import android.support.annotation.NonNull;
-import android.support.design.widget.TabLayout;
-import android.support.v4.view.PagerAdapter;
-// `AppCompatDialogFragment` is used instead of `DialogFragment` to avoid an error on API <=22.
-import android.support.v7.app.AppCompatDialogFragment;
-import android.text.SpannableStringBuilder;
-import android.text.Spanned;
-import android.text.style.ForegroundColorSpan;
-import android.view.LayoutInflater;
-import android.view.View;
-import android.view.ViewGroup;
-import android.view.WindowManager;
-import android.widget.TextView;
-
-import com.stoutner.privacybrowser.R;
-import com.stoutner.privacybrowser.activities.MainWebViewActivity;
-import com.stoutner.privacybrowser.definitions.WrapVerticalContentViewPager;
-import com.stoutner.privacybrowser.helpers.DomainsDatabaseHelper;
-
-import java.text.DateFormat;
-import java.util.Date;
-
-public class PinnedSslCertificateMismatchDialog extends AppCompatDialogFragment {
- // Instantiate the class variables.
- private PinnedSslCertificateMismatchListener pinnedSslCertificateMismatchListener;
- private LayoutInflater layoutInflater;
- private String currentSslIssuedToCNameString;
- private String currentSslIssuedToONameString;
- private String currentSslIssuedToUNameString;
- private String currentSslIssuedByCNameString;
- private String currentSslIssuedByONameString;
- private String currentSslIssuedByUNameString;
- private Date currentSslStartDate;
- private Date currentSslEndDate;
-
- // The public interface is used to send information back to the parent activity.
- public interface PinnedSslCertificateMismatchListener {
- void onSslMismatchBack();
-
- void onSslMismatchProceed();
- }
-
- // Check to make sure that the parent activity implements the listener.
- public void onAttach(Context context) {
- // Run the default commands.
- super.onAttach(context);
-
- // Get a handle for `PinnedSslCertificateMismatchListener` from the launching context.
- pinnedSslCertificateMismatchListener = (PinnedSslCertificateMismatchListener) context;
- }
-
- // `@SuppressLing("InflateParams")` removes the warning about using `null` as the parent view group when inflating the `AlertDialog`.
- @SuppressLint("InflateParams")
- @Override
- @NonNull
- public Dialog onCreateDialog(Bundle savedInstanceState) {
- // Remove the incorrect lint warning that `getActivity()` might be null.
- assert getActivity() != null;
-
- // Get the activity's layout inflater.
- layoutInflater = getActivity().getLayoutInflater();
-
- // Use an alert dialog builder to create the alert dialog.
- AlertDialog.Builder dialogBuilder;
-
- // Set the style according to the theme.
- if (MainWebViewActivity.darkTheme) {
- // Set the dialog theme.
- dialogBuilder = new AlertDialog.Builder(getActivity(), R.style.PrivacyBrowserAlertDialogDark);
-
- // Set the icon.
- dialogBuilder.setIcon(R.drawable.ssl_certificate_enabled_dark);
- } else {
- // Set the dialog theme.
- dialogBuilder = new AlertDialog.Builder(getActivity(), R.style.PrivacyBrowserAlertDialogLight);
-
- // Set the icon.
- dialogBuilder.setIcon(R.drawable.ssl_certificate_enabled_light);
- }
-
- // Setup the neutral button.
- dialogBuilder.setNeutralButton(R.string.update_ssl, (DialogInterface dialog, int which) -> {
- // Initialize the `long` date variables. If the date is `null`, a long value of `0` will be stored in the Domains database entry.
- long currentSslStartDateLong = 0;
- long currentSslEndDateLong = 0;
-
- // Convert the `Dates` into `longs`.
- if (currentSslStartDate != null) {
- currentSslStartDateLong = currentSslStartDate.getTime();
- }
-
- if (currentSslEndDate != null) {
- currentSslEndDateLong = currentSslEndDate.getTime();
- }
-
- // Initialize the database handler. The `0` specifies the database version, but that is ignored and set instead using a constant in `DomainsDatabaseHelper`.
- DomainsDatabaseHelper domainsDatabaseHelper = new DomainsDatabaseHelper(getContext(), null, null, 0);
-
- // Update the pinned SSL certificate for this domain.
- domainsDatabaseHelper.updateCertificate(MainWebViewActivity.domainSettingsDatabaseId, currentSslIssuedToCNameString, currentSslIssuedToONameString, currentSslIssuedToUNameString,
- currentSslIssuedByCNameString, currentSslIssuedByONameString, currentSslIssuedByUNameString, currentSslStartDateLong, currentSslEndDateLong);
-
- // Update the pinned SSL certificate global variables to match the information that is now in the database.
- MainWebViewActivity.pinnedDomainSslIssuedToCNameString = currentSslIssuedToCNameString;
- MainWebViewActivity.pinnedDomainSslIssuedToONameString = currentSslIssuedToONameString;
- MainWebViewActivity.pinnedDomainSslIssuedToUNameString = currentSslIssuedToUNameString;
- MainWebViewActivity.pinnedDomainSslIssuedByCNameString = currentSslIssuedByCNameString;
- MainWebViewActivity.pinnedDomainSslIssuedByONameString = currentSslIssuedByONameString;
- MainWebViewActivity.pinnedDomainSslIssuedByUNameString = currentSslIssuedByUNameString;
- MainWebViewActivity.pinnedDomainSslStartDate = currentSslStartDate;
- MainWebViewActivity.pinnedDomainSslEndDate = currentSslEndDate;
- });
-
- // Setup the negative button.
- dialogBuilder.setNegativeButton(R.string.back, (DialogInterface dialog, int which) -> {
- // Call the `onSslMismatchBack` public interface to send the `WebView` back one page.
- pinnedSslCertificateMismatchListener.onSslMismatchBack();
- });
-
- // Setup the positive button.
- dialogBuilder.setPositiveButton(R.string.proceed, (DialogInterface dialog, int which) -> {
- // Call the `onSslMismatchProceed` public interface.
- pinnedSslCertificateMismatchListener.onSslMismatchProceed();
- });
-
- // Set the title.
- dialogBuilder.setTitle(R.string.ssl_certificate_mismatch);
-
- // Set the layout. The parent view is `null` because it will be assigned by `AlertDialog`.
- dialogBuilder.setView(layoutInflater.inflate(R.layout.pinned_ssl_certificate_mismatch_linearlayout, null));
-
- // Create an alert dialog from the alert dialog builder.
- final AlertDialog alertDialog = dialogBuilder.create();
-
- // Disable screenshots if not allowed.
- if (!MainWebViewActivity.allowScreenshots) {
- // Remove the warning below that `getWindow()` might be null.
- assert alertDialog.getWindow() != null;
-
- // Disable screenshots.
- alertDialog.getWindow().addFlags(WindowManager.LayoutParams.FLAG_SECURE);
- }
-
- // Show the alert dialog so the items in the layout can be modified.
- alertDialog.show();
-
- // Setup the view pager.
- WrapVerticalContentViewPager wrapVerticalContentViewPager = alertDialog.findViewById(R.id.pinned_ssl_certificate_mismatch_viewpager);
- wrapVerticalContentViewPager.setAdapter(new pagerAdapter());
-
- // Setup the tab layout and connect it to the view pager.
- TabLayout tabLayout = alertDialog.findViewById(R.id.pinned_ssl_certificate_mismatch_tablayout);
- tabLayout.setupWithViewPager(wrapVerticalContentViewPager);
-
- // `onCreateDialog()` requires the return of an `AlertDialog`.
- return alertDialog;
- }
-
- private class pagerAdapter extends PagerAdapter {
- @Override
- public boolean isViewFromObject(@NonNull View view, @NonNull Object object) {
- // Check to see if the `View` and the `Object` are the same.
- return (view == object);
- }
-
- @Override
- public int getCount() {
- // There are two tabs.
- return 2;
- }
-
- @Override
- public CharSequence getPageTitle(int position) {
- // Return the current tab title.
- if (position == 0) { // The current SSL certificate tab.
- return getString(R.string.current_ssl);
- } else { // The pinned SSL certificate tab.
- return getString(R.string.pinned_ssl);
- }
- }
-
- @Override
- @NonNull
- public Object instantiateItem(@NonNull ViewGroup container, int position) {
- // Inflate the `ScrollView` for this tab.
- ViewGroup tabViewGroup = (ViewGroup) layoutInflater.inflate(R.layout.pinned_ssl_certificate_mismatch_scrollview, container, false);
-
- // Get handles for the `TextViews`.
- TextView issuedToCNameTextView = tabViewGroup.findViewById(R.id.issued_to_cname);
- TextView issuedToONameTextView = tabViewGroup.findViewById(R.id.issued_to_oname);
- TextView issuedToUNameTextView = tabViewGroup.findViewById(R.id.issued_to_uname);
- TextView issuedByCNameTextView = tabViewGroup.findViewById(R.id.issued_by_cname);
- TextView issuedByONameTextView = tabViewGroup.findViewById(R.id.issued_by_oname);
- TextView issuedByUNameTextView = tabViewGroup.findViewById(R.id.issued_by_uname);
- TextView startDateTextView = tabViewGroup.findViewById(R.id.start_date);
- TextView endDateTextView = tabViewGroup.findViewById(R.id.end_date);
-
- // Setup the labels.
- String cNameLabel = getString(R.string.common_name) + " ";
- String oNameLabel = getString(R.string.organization) + " ";
- String uNameLabel = getString(R.string.organizational_unit) + " ";
- String startDateLabel = getString(R.string.start_date) + " ";
- String endDateLabel = getString(R.string.end_date) + " ";
-
- // Get the current website SSL certificate.
- SslCertificate sslCertificate = MainWebViewActivity.sslCertificate;
-
- // Extract the individual pieces of information from the current website SSL certificate if it is not null.
- if (sslCertificate != null) {
- currentSslIssuedToCNameString = sslCertificate.getIssuedTo().getCName();
- currentSslIssuedToONameString = sslCertificate.getIssuedTo().getOName();
- currentSslIssuedToUNameString = sslCertificate.getIssuedTo().getUName();
- currentSslIssuedByCNameString = sslCertificate.getIssuedBy().getCName();
- currentSslIssuedByONameString = sslCertificate.getIssuedBy().getOName();
- currentSslIssuedByUNameString = sslCertificate.getIssuedBy().getUName();
- currentSslStartDate = sslCertificate.getValidNotBeforeDate();
- currentSslEndDate = sslCertificate.getValidNotAfterDate();
- } else {
- // Initialize the current website SSL certificate variables with blank information.
- currentSslIssuedToCNameString = "";
- currentSslIssuedToONameString = "";
- currentSslIssuedToUNameString = "";
- currentSslIssuedByCNameString = "";
- currentSslIssuedByONameString = "";
- currentSslIssuedByUNameString = "";
- }
-
- // Initialize the `SpannableStringBuilders`.
- SpannableStringBuilder issuedToCNameStringBuilder;
- SpannableStringBuilder issuedToONameStringBuilder;
- SpannableStringBuilder issuedToUNameStringBuilder;
- SpannableStringBuilder issuedByCNameStringBuilder;
- SpannableStringBuilder issuedByONameStringBuilder;
- SpannableStringBuilder issuedByUNameStringBuilder;
- SpannableStringBuilder startDateStringBuilder;
- SpannableStringBuilder endDateStringBuilder;
-
- // Setup the `SpannableStringBuilders` for each tab.
- if (position == 0) { // Setup the current SSL certificate tab.
- issuedToCNameStringBuilder = new SpannableStringBuilder(cNameLabel + currentSslIssuedToCNameString);
- issuedToONameStringBuilder = new SpannableStringBuilder(oNameLabel + currentSslIssuedToONameString);
- issuedToUNameStringBuilder = new SpannableStringBuilder(uNameLabel + currentSslIssuedToUNameString);
- issuedByCNameStringBuilder = new SpannableStringBuilder(cNameLabel + currentSslIssuedByCNameString);
- issuedByONameStringBuilder = new SpannableStringBuilder(oNameLabel + currentSslIssuedByONameString);
- issuedByUNameStringBuilder = new SpannableStringBuilder(uNameLabel + currentSslIssuedByUNameString);
-
- // Set the dates if they aren't `null`.
- if (currentSslStartDate == null) {
- startDateStringBuilder = new SpannableStringBuilder(startDateLabel);
- } else {
- startDateStringBuilder = new SpannableStringBuilder(startDateLabel + DateFormat.getDateTimeInstance(DateFormat.MEDIUM, DateFormat.LONG).format(currentSslStartDate));
- }
-
- if (currentSslEndDate == null) {
- endDateStringBuilder = new SpannableStringBuilder(endDateLabel);
- } else {
- endDateStringBuilder = new SpannableStringBuilder(endDateLabel + DateFormat.getDateTimeInstance(DateFormat.MEDIUM, DateFormat.LONG).format(currentSslEndDate));
- }
- } else { // Setup the pinned SSL certificate tab.
- issuedToCNameStringBuilder = new SpannableStringBuilder(cNameLabel + MainWebViewActivity.pinnedDomainSslIssuedToCNameString);
- issuedToONameStringBuilder = new SpannableStringBuilder(oNameLabel + MainWebViewActivity.pinnedDomainSslIssuedToONameString);
- issuedToUNameStringBuilder = new SpannableStringBuilder(uNameLabel + MainWebViewActivity.pinnedDomainSslIssuedToUNameString);
- issuedByCNameStringBuilder = new SpannableStringBuilder(cNameLabel + MainWebViewActivity.pinnedDomainSslIssuedByCNameString);
- issuedByONameStringBuilder = new SpannableStringBuilder(oNameLabel + MainWebViewActivity.pinnedDomainSslIssuedByONameString);
- issuedByUNameStringBuilder = new SpannableStringBuilder(uNameLabel + MainWebViewActivity.pinnedDomainSslIssuedByUNameString);
-
- // Set the dates if they aren't `null`.
- if (MainWebViewActivity.pinnedDomainSslStartDate == null) {
- startDateStringBuilder = new SpannableStringBuilder(startDateLabel);
- } else {
- startDateStringBuilder = new SpannableStringBuilder(startDateLabel + DateFormat.getDateTimeInstance(DateFormat.MEDIUM, DateFormat.LONG)
- .format(MainWebViewActivity.pinnedDomainSslStartDate));
- }
-
- if (MainWebViewActivity.pinnedDomainSslEndDate == null) {
- endDateStringBuilder = new SpannableStringBuilder(endDateLabel);
- } else {
- endDateStringBuilder = new SpannableStringBuilder(endDateLabel + DateFormat.getDateTimeInstance(DateFormat.MEDIUM, DateFormat.LONG).format(MainWebViewActivity.pinnedDomainSslEndDate));
- }
- }
-
- // Create a red `ForegroundColorSpan`. We have to use the deprecated `getColor` until API >= 23.
- @SuppressWarnings("deprecation") ForegroundColorSpan redColorSpan = new ForegroundColorSpan(getResources().getColor(R.color.red_a700));
-
- // Create a blue `ForegroundColorSpan`.
- ForegroundColorSpan blueColorSpan;
-
- // Set `blueColorSpan` according to the theme. We have to use the deprecated `getColor()` until API >= 23.
- if (MainWebViewActivity.darkTheme) {
- //noinspection deprecation
- blueColorSpan = new ForegroundColorSpan(getResources().getColor(R.color.blue_400));
- } else {
- //noinspection deprecation
- blueColorSpan = new ForegroundColorSpan(getResources().getColor(R.color.blue_700));
- }
-
- // Configure the spans to display conflicting information in red. `SPAN_INCLUSIVE_INCLUSIVE` allows the span to grow in either direction.
- if (currentSslIssuedToCNameString.equals(MainWebViewActivity.pinnedDomainSslIssuedToCNameString)) {
- issuedToCNameStringBuilder.setSpan(blueColorSpan, cNameLabel.length(), issuedToCNameStringBuilder.length(), Spanned.SPAN_INCLUSIVE_INCLUSIVE);
- } else {
- issuedToCNameStringBuilder.setSpan(redColorSpan, cNameLabel.length(), issuedToCNameStringBuilder.length(), Spanned.SPAN_INCLUSIVE_INCLUSIVE);
- }
-
- if (currentSslIssuedToONameString.equals(MainWebViewActivity.pinnedDomainSslIssuedToONameString)) {
- issuedToONameStringBuilder.setSpan(blueColorSpan, oNameLabel.length(), issuedToONameStringBuilder.length(), Spanned.SPAN_INCLUSIVE_INCLUSIVE);
- } else {
- issuedToONameStringBuilder.setSpan(redColorSpan, oNameLabel.length(), issuedToONameStringBuilder.length(), Spanned.SPAN_INCLUSIVE_INCLUSIVE);
- }
-
- if (currentSslIssuedToUNameString.equals(MainWebViewActivity.pinnedDomainSslIssuedToUNameString)) {
- issuedToUNameStringBuilder.setSpan(blueColorSpan, uNameLabel.length(), issuedToUNameStringBuilder.length(), Spanned.SPAN_INCLUSIVE_INCLUSIVE);
- } else {
- issuedToUNameStringBuilder.setSpan(redColorSpan, uNameLabel.length(), issuedToUNameStringBuilder.length(), Spanned.SPAN_INCLUSIVE_INCLUSIVE);
- }
-
- if (currentSslIssuedByCNameString.equals(MainWebViewActivity.pinnedDomainSslIssuedByCNameString)) {
- issuedByCNameStringBuilder.setSpan(blueColorSpan, cNameLabel.length(), issuedByCNameStringBuilder.length(), Spanned.SPAN_INCLUSIVE_INCLUSIVE);
- } else {
- issuedByCNameStringBuilder.setSpan(redColorSpan, cNameLabel.length(), issuedByCNameStringBuilder.length(), Spanned.SPAN_INCLUSIVE_INCLUSIVE);
- }
-
- if (currentSslIssuedByONameString.equals(MainWebViewActivity.pinnedDomainSslIssuedByONameString)) {
- issuedByONameStringBuilder.setSpan(blueColorSpan, oNameLabel.length(), issuedByONameStringBuilder.length(), Spanned.SPAN_INCLUSIVE_INCLUSIVE);
- } else {
- issuedByONameStringBuilder.setSpan(redColorSpan, oNameLabel.length(), issuedByONameStringBuilder.length(), Spanned.SPAN_INCLUSIVE_INCLUSIVE);
- }
-
- if (currentSslIssuedByUNameString.equals(MainWebViewActivity.pinnedDomainSslIssuedByUNameString)) {
- issuedByUNameStringBuilder.setSpan(blueColorSpan, uNameLabel.length(), issuedByUNameStringBuilder.length(), Spanned.SPAN_INCLUSIVE_INCLUSIVE);
- } else {
- issuedByUNameStringBuilder.setSpan(redColorSpan, uNameLabel.length(), issuedByUNameStringBuilder.length(), Spanned.SPAN_INCLUSIVE_INCLUSIVE);
- }
-
- if ((currentSslStartDate != null) && (MainWebViewActivity.pinnedDomainSslStartDate != null) && currentSslStartDate.equals(MainWebViewActivity.pinnedDomainSslStartDate)) {
- startDateStringBuilder.setSpan(blueColorSpan, startDateLabel.length(), startDateStringBuilder.length(), Spanned.SPAN_INCLUSIVE_INCLUSIVE);
- } else {
- startDateStringBuilder.setSpan(redColorSpan, startDateLabel.length(), startDateStringBuilder.length(), Spanned.SPAN_INCLUSIVE_INCLUSIVE);
- }
-
- if ((currentSslEndDate != null) && (MainWebViewActivity.pinnedDomainSslEndDate != null) && currentSslEndDate.equals(MainWebViewActivity.pinnedDomainSslEndDate)) {
- endDateStringBuilder.setSpan(blueColorSpan, endDateLabel.length(), endDateStringBuilder.length(), Spanned.SPAN_INCLUSIVE_INCLUSIVE);
- } else {
- endDateStringBuilder.setSpan(redColorSpan, endDateLabel.length(), endDateStringBuilder.length(), Spanned.SPAN_INCLUSIVE_INCLUSIVE);
- }
-
- // Display the strings.
- issuedToCNameTextView.setText(issuedToCNameStringBuilder);
- issuedToONameTextView.setText(issuedToONameStringBuilder);
- issuedToUNameTextView.setText(issuedToUNameStringBuilder);
- issuedByCNameTextView.setText(issuedByCNameStringBuilder);
- issuedByONameTextView.setText(issuedByONameStringBuilder);
- issuedByUNameTextView.setText(issuedByUNameStringBuilder);
- startDateTextView.setText(startDateStringBuilder);
- endDateTextView.setText(endDateStringBuilder);
-
- // Display the tab.
- container.addView(tabViewGroup);
-
- // Make it so.
- return tabViewGroup;
- }
- }
-}
/*
- * Copyright © 2016-2018 Soren Stoutner <soren@stoutner.com>.
+ * Copyright © 2016-2019 Soren Stoutner <soren@stoutner.com>.
*
* This file is part of Privacy Browser <https://www.stoutner.com/privacy-browser>.
*
package com.stoutner.privacybrowser.dialogs;
import android.annotation.SuppressLint;
+import android.app.Activity;
import android.app.AlertDialog;
import android.app.Dialog;
import android.content.Context;
import android.content.DialogInterface;
+import android.net.Uri;
import android.net.http.SslCertificate;
import android.net.http.SslError;
+import android.os.AsyncTask;
import android.os.Bundle;
import android.support.annotation.NonNull;
// `AppCompatDialogFragment` is used instead of `DialogFragment` to avoid an error on API <=22.
import com.stoutner.privacybrowser.R;
import com.stoutner.privacybrowser.activities.MainWebViewActivity;
+import java.lang.ref.WeakReference;
+import java.net.InetAddress;
+import java.net.UnknownHostException;
import java.text.DateFormat;
import java.util.Date;
// Get the components of the SSL error message from the bundle.
int primaryErrorInt = getArguments().getInt("PrimaryErrorInt");
- String urlWithError = getArguments().getString("UrlWithError");
+ String urlWithErrors = getArguments().getString("UrlWithError");
String issuedToCName = getArguments().getString("IssuedToCName");
String issuedToOName = getArguments().getString("IssuedToOName");
String issuedToUName = getArguments().getString("IssuedToUName");
alertDialog.getWindow().addFlags(WindowManager.LayoutParams.FLAG_SECURE);
}
- // We have to show the alert dialog before we can modify the content.
+ // Get a URI for the URL with errors.
+ Uri uriWithErrors = Uri.parse(urlWithErrors);
+
+ // Get the IP addresses for the URI.
+ new GetIpAddresses(getActivity(), alertDialog).execute(uriWithErrors.getHost());
+
+ // The alert dialog must be shown before the contents can be modified.
alertDialog.show();
// Get handles for the `TextViews`
TextView primaryErrorTextView = alertDialog.findViewById(R.id.primary_error);
- TextView urlTextView = alertDialog.findViewById(R.id.url_error_dialog);
- TextView issuedToCNameTextView = alertDialog.findViewById(R.id.issued_to_cname_error_dialog);
- TextView issuedToONameTextView = alertDialog.findViewById(R.id.issued_to_oname_error_dialog);
- TextView issuedToUNameTextView = alertDialog.findViewById(R.id.issued_to_uname_error_dialog);
+ TextView urlTextView = alertDialog.findViewById(R.id.url);
+ TextView issuedToCNameTextView = alertDialog.findViewById(R.id.issued_to_cname);
+ TextView issuedToONameTextView = alertDialog.findViewById(R.id.issued_to_oname);
+ TextView issuedToUNameTextView = alertDialog.findViewById(R.id.issued_to_uname);
TextView issuedByTextView = alertDialog.findViewById(R.id.issued_by_textview);
- TextView issuedByCNameTextView = alertDialog.findViewById(R.id.issued_by_cname_error_dialog);
- TextView issuedByONameTextView = alertDialog.findViewById(R.id.issued_by_oname_error_dialog);
- TextView issuedByUNameTextView = alertDialog.findViewById(R.id.issued_by_uname_error_dialog);
+ TextView issuedByCNameTextView = alertDialog.findViewById(R.id.issued_by_cname);
+ TextView issuedByONameTextView = alertDialog.findViewById(R.id.issued_by_oname);
+ TextView issuedByUNameTextView = alertDialog.findViewById(R.id.issued_by_uname);
TextView validDatesTextView = alertDialog.findViewById(R.id.valid_dates_textview);
- TextView startDateTextView = alertDialog.findViewById(R.id.start_date_error_dialog);
- TextView endDateTextView = alertDialog.findViewById(R.id.end_date_error_dialog);
+ TextView startDateTextView = alertDialog.findViewById(R.id.start_date);
+ TextView endDateTextView = alertDialog.findViewById(R.id.end_date);
// Setup the common strings.
String urlLabel = getString(R.string.url_label) + " ";
String startDateLabel = getString(R.string.start_date) + " ";
String endDateLabel = getString(R.string.end_date) + " ";
- // Create a `SpannableStringBuilder` for each `TextView` that needs multiple colors of text.
- SpannableStringBuilder urlStringBuilder = new SpannableStringBuilder(urlLabel + urlWithError);
+ // Create a spannable string builder for each text view that needs multiple colors of text.
+ SpannableStringBuilder urlStringBuilder = new SpannableStringBuilder(urlLabel + urlWithErrors);
SpannableStringBuilder issuedToCNameStringBuilder = new SpannableStringBuilder(cNameLabel + issuedToCName);
SpannableStringBuilder issuedToONameStringBuilder = new SpannableStringBuilder(oNameLabel + issuedToOName);
SpannableStringBuilder issuedToUNameStringBuilder = new SpannableStringBuilder(uNameLabel + issuedToUName);
SpannableStringBuilder startDateStringBuilder = new SpannableStringBuilder(startDateLabel + startDate);
SpannableStringBuilder endDateStringBuilder = new SpannableStringBuilder((endDateLabel + endDate));
- // Create a red `ForegroundColorSpan`. We have to use the deprecated `getColor` until API >= 23.
+ // Create a red foreground color span. The deprecated `getResources().getColor` must be used until the minimum API >= 23.
@SuppressWarnings("deprecation") ForegroundColorSpan redColorSpan = new ForegroundColorSpan(getResources().getColor(R.color.red_a700));
// Create a blue `ForegroundColorSpan`.
ForegroundColorSpan blueColorSpan;
- // Set `blueColorSpan` according to the theme. We have to use the deprecated `getColor()` until API >= 23.
+ // Set a blue color span according to the theme. The deprecated `getResources().getColor` must be used until the minimum API >= 23.
if (MainWebViewActivity.darkTheme) {
//noinspection deprecation
blueColorSpan = new ForegroundColorSpan(getResources().getColor(R.color.blue_400));
break;
case SslError.SSL_UNTRUSTED:
- // Change the `issuesByTextView` text to red. We have to use the deprecated `getColor()` until API >= 23.
+ // Change the issued by text view text to red. The deprecated `getResources().getColor` must be used until the minimum API >= 23.
issuedByTextView.setTextColor(getResources().getColor(R.color.red_a700));
// Change the issued by span color to red.
break;
case SslError.SSL_DATE_INVALID:
- // Change the `validDatesTextView` text to red. We have to use the deprecated `getColor()` until API >= 23.
+ // Change the valid dates text view text to red. The deprecated `getResources().getColor` must be used until the minimum API >= 23.
validDatesTextView.setTextColor(getResources().getColor(R.color.red_a700));
// Change the date span colors to red.
startDateTextView.setText(startDateStringBuilder);
endDateTextView.setText(endDateStringBuilder);
- // `onCreateDialog` requires the return of an `AlertDialog`.
+ // `onCreateDialog` requires the return of an alert dialog.
return alertDialog;
}
+
+
+ // This must run asynchronously because it involves a network request. `String` declares the parameters. `Void` does not declare progress units. `SpannableStringBuilder` contains the results.
+ private static class GetIpAddresses extends AsyncTask<String, Void, SpannableStringBuilder> {
+ // The weak references are used to determine if the activity or the alert dialog have disappeared while the AsyncTask is running.
+ private WeakReference<Activity> activityWeakReference;
+ private WeakReference<AlertDialog> alertDialogWeakReference;
+
+ GetIpAddresses(Activity activity, AlertDialog alertDialog) {
+ // Populate the weak references.
+ activityWeakReference = new WeakReference<>(activity);
+ alertDialogWeakReference = new WeakReference<>(alertDialog);
+ }
+
+ @Override
+ protected SpannableStringBuilder doInBackground(String... domainName) {
+ // Get handles for the activity and the alert dialog.
+ Activity activity = activityWeakReference.get();
+ AlertDialog alertDialog = alertDialogWeakReference.get();
+
+ // Abort if the activity or the dialog is gone.
+ if ((activity == null) || (activity.isFinishing()) || (alertDialog == null)) {
+ return new SpannableStringBuilder();
+ }
+
+ // Initialize an IP address string builder.
+ StringBuilder ipAddresses = new StringBuilder();
+
+ // Get an array with the IP addresses for the host.
+ try {
+ // Get an array with all the IP addresses for the domain.
+ InetAddress[] inetAddressesArray = InetAddress.getAllByName(domainName[0]);
+
+ // Add each IP address to the string builder.
+ for (InetAddress inetAddress : inetAddressesArray) {
+ if (ipAddresses.length() == 0) { // This is the first IP address.
+ // Add the IP Address to the string builder.
+ ipAddresses.append(inetAddress.getHostAddress());
+ } else { // This is not the first IP address.
+ // Add a line break to the string builder first.
+ ipAddresses.append("\n");
+
+ // Add the IP address to the string builder.
+ ipAddresses.append(inetAddress.getHostAddress());
+ }
+ }
+ } catch (UnknownHostException exception) {
+ // Do nothing.
+ }
+
+ // Set the label.
+ String ipAddressesLabel = activity.getString(R.string.ip_addresses) + " ";
+
+ // Create a spannable string builder.
+ SpannableStringBuilder ipAddressesStringBuilder = new SpannableStringBuilder(ipAddressesLabel + ipAddresses);
+
+ // Create a blue foreground color span.
+ ForegroundColorSpan blueColorSpan;
+
+ // Set the blue color span according to the theme. The deprecated `getColor()` must be used until the minimum API >= 23.
+ if (MainWebViewActivity.darkTheme) {
+ //noinspection deprecation
+ blueColorSpan = new ForegroundColorSpan(activity.getResources().getColor(R.color.blue_400));
+ } else {
+ //noinspection deprecation
+ blueColorSpan = new ForegroundColorSpan(activity.getResources().getColor(R.color.blue_700));
+ }
+
+ // Set the string builder to display the certificate information in blue. `SPAN_INCLUSIVE_INCLUSIVE` allows the span to grow in either direction.
+ ipAddressesStringBuilder.setSpan(blueColorSpan, ipAddressesLabel.length(), ipAddressesStringBuilder.length(), Spanned.SPAN_INCLUSIVE_INCLUSIVE);
+
+ // Return the formatted string.
+ return ipAddressesStringBuilder;
+ }
+
+ // `onPostExecute()` operates on the UI thread.
+ @Override
+ protected void onPostExecute(SpannableStringBuilder ipAddresses) {
+ // Get handles for the activity and the alert dialog.
+ Activity activity = activityWeakReference.get();
+ AlertDialog alertDialog = alertDialogWeakReference.get();
+
+ // Abort if the activity or the alert dialog is gone.
+ if ((activity == null) || (activity.isFinishing()) || (alertDialog == null)) {
+ return;
+ }
+
+ // Get a handle for the IP addresses text view.
+ TextView ipAddressesTextView = alertDialog.findViewById(R.id.ip_addresses);
+
+ // Populate the IP addresses text view.
+ ipAddressesTextView.setText(ipAddresses);
+ }
+ }
}
package com.stoutner.privacybrowser.dialogs;
import android.annotation.SuppressLint;
-import android.app.Activity;
import android.app.AlertDialog;
import android.app.Dialog;
import android.app.DialogFragment;
import android.graphics.drawable.Drawable;
import android.net.Uri;
import android.net.http.SslCertificate;
-import android.os.AsyncTask;
import android.os.Bundle;
import android.text.SpannableStringBuilder;
import android.text.Spanned;
import com.stoutner.privacybrowser.activities.MainWebViewActivity;
import com.stoutner.privacybrowser.R;
-
-import java.lang.ref.WeakReference;
-import java.net.InetAddress;
-import java.net.UnknownHostException;
import java.text.DateFormat;
import java.util.Calendar;
import java.util.Date;
public class ViewSslCertificateDialog extends DialogFragment {
public Dialog onCreateDialog(Bundle savedInstanceState) {
// Get the activity's layout inflater.
- LayoutInflater layoutInflater = getActivity().getLayoutInflater();
-
- // Create a drawable version of the favorite icon.
- Drawable favoriteIconDrawable = new BitmapDrawable(getResources(), MainWebViewActivity.favoriteIconBitmap);
+ LayoutInflater layoutInflater = getActivity().getLayoutInflater();
// Use a builder to create the alert dialog.
AlertDialog.Builder dialogBuilder;
dialogBuilder = new AlertDialog.Builder(getActivity(), R.style.PrivacyBrowserAlertDialogLight);
}
+ // Create a drawable version of the favorite icon.
+ Drawable favoriteIconDrawable = new BitmapDrawable(getResources(), MainWebViewActivity.favoriteIconBitmap);
+
// Set the icon.
dialogBuilder.setIcon(favoriteIconDrawable);
// Setup the labels.
String domainLabel = getString(R.string.domain_label) + " ";
+ String ipAddressesLabel = getString(R.string.ip_addresses) + " ";
String cNameLabel = getString(R.string.common_name) + " ";
String oNameLabel = getString(R.string.organization) + " ";
String uNameLabel = getString(R.string.organizational_unit) + " ";
// Extract the domain name from the URI.
String domainString = uri.getHost();
- // Get the IP addresses.
- new GetIpAddresses(getActivity(), alertDialog).execute(domainString);
-
// Get the SSL certificate.
SslCertificate sslCertificate = MainWebViewActivity.sslCertificate;
// Create spannable string builders for each text view that needs multiple colors of text.
SpannableStringBuilder domainStringBuilder = new SpannableStringBuilder(domainLabel + domainString);
+ SpannableStringBuilder ipAddressesStringBuilder = new SpannableStringBuilder(ipAddressesLabel + MainWebViewActivity.currentHostIpAddresses);
SpannableStringBuilder issuedToCNameStringBuilder = new SpannableStringBuilder(cNameLabel + issuedToCName);
SpannableStringBuilder issuedToONameStringBuilder = new SpannableStringBuilder(oNameLabel + issuedToOName);
SpannableStringBuilder issuedToUNameStringBuilder = new SpannableStringBuilder(uNameLabel + issuedToUName);
// Remove the incorrect lint error that `.equals` might produce a NullPointerException.
assert domainString != null;
- // Formet the `domainString` and `issuedToCName` colors.
+ // Formet the domain string and issued to CName colors.
if (domainString.equals(issuedToCName)) { // `domainString` and `issuedToCName` match.
// Set the strings to be blue.
domainStringBuilder.setSpan(blueColorSpan, domainLabel.length(), domainStringBuilder.length(), Spanned.SPAN_INCLUSIVE_INCLUSIVE);
issuedToCNameStringBuilder.setSpan(redColorSpan, cNameLabel.length(), issuedToCNameStringBuilder.length(), Spanned.SPAN_INCLUSIVE_INCLUSIVE);
}
- // Set the issued to and issued by spans to display the certificate information in blue. `SPAN_INCLUSIVE_INCLUSIVE` allows the span to grow in either direction.
+ // Set the IP addresses, issued to, and issued by spans to display the certificate information in blue. `SPAN_INCLUSIVE_INCLUSIVE` allows the span to grow in either direction.
+ ipAddressesStringBuilder.setSpan(blueColorSpan, ipAddressesLabel.length(), ipAddressesStringBuilder.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);
+ // Get the current date.
Date currentDate = Calendar.getInstance().getTime();
// Format the start date color. `SPAN_INCLUSIVE_INCLUSIVE` allows the span to grow in either direction.
// Display the strings.
domainTextView.setText(domainStringBuilder);
- ipAddressesTextView.setText(getString(R.string.ip_addresses));
+ ipAddressesTextView.setText(ipAddressesStringBuilder);
issuedToCNameTextView.setText(issuedToCNameStringBuilder);
issuedToONameTextView.setText(issuedToONameStringBuilder);
issuedToUNameTextView.setText(issuedToUNameStringBuilder);
startDateTextView.setText(startDateStringBuilder);
endDateTextView.setText(endDateStringBuilder);
- // `onCreateDialog` requires the return of an `AlertDialog`.
+ // `onCreateDialog` requires the return of an alert dialog.
return alertDialog;
}
}
-
- // This must run asynchronously because it involves a network request. `String` declares the parameters. `Void` does not declare progress units. `String` contains the results.
- private static class GetIpAddresses extends AsyncTask<String, Void, SpannableStringBuilder> {
- // The weak references are used to determine if the activity or the alert dialog have disappeared while the AsyncTask is running.
- private WeakReference<Activity> activityWeakReference;
- private WeakReference<AlertDialog> alertDialogWeakReference;
-
- GetIpAddresses(Activity activity, AlertDialog alertDialog) {
- // Populate the weak references.
- activityWeakReference = new WeakReference<>(activity);
- alertDialogWeakReference = new WeakReference<>(alertDialog);
- }
-
- @Override
- protected SpannableStringBuilder doInBackground(String... domainName) {
- // Get handles for the activity and the alert dialog.
- Activity activity = activityWeakReference.get();
- AlertDialog alertDialog = alertDialogWeakReference.get();
-
- // Abort if the activity or the dialog is gone.
- if ((activity == null) || (activity.isFinishing()) || (alertDialog == null)) {
- return new SpannableStringBuilder();
- }
-
- // Initialize an IP address string builder.
- StringBuilder ipAddresses = new StringBuilder();
-
- // Get an array with the IP addresses for the host.
- try {
- // Get an array with all the IP addresses for the domain.
- InetAddress[] inetAddressesArray = InetAddress.getAllByName(domainName[0]);
-
- // Add each IP address to the string builder.
- for (InetAddress inetAddress : inetAddressesArray) {
- if (ipAddresses.length() == 0) { // This is the first IP address.
- // Add the IP Address to the string builder.
- ipAddresses.append(inetAddress.getHostAddress());
- } else { // This is not the first IP address.
- // Add a line break to the string builder first.
- ipAddresses.append("\n");
-
- // Add the IP address to the string builder.
- ipAddresses.append(inetAddress.getHostAddress());
- }
- }
- } catch (UnknownHostException exception) {
- // Do nothing.
- }
-
- // Set the label.
- String ipAddressesLabel = activity.getString(R.string.ip_addresses) + " ";
-
- // Create a spannable string builder.
- SpannableStringBuilder ipAddressesStringBuilder = new SpannableStringBuilder(ipAddressesLabel + ipAddresses);
-
- // Create a blue foreground color span.
- ForegroundColorSpan blueColorSpan;
-
- // Set the blue color span according to the theme. The deprecated `getColor()` must be used until the minimum API >= 23.
- if (MainWebViewActivity.darkTheme) {
- //noinspection deprecation
- blueColorSpan = new ForegroundColorSpan(activity.getResources().getColor(R.color.blue_400));
- } else {
- //noinspection deprecation
- blueColorSpan = new ForegroundColorSpan(activity.getResources().getColor(R.color.blue_700));
- }
-
- // Set the string builder to display the certificate information in blue. `SPAN_INCLUSIVE_INCLUSIVE` allows the span to grow in either direction.
- ipAddressesStringBuilder.setSpan(blueColorSpan, ipAddressesLabel.length(), ipAddressesStringBuilder.length(), Spanned.SPAN_INCLUSIVE_INCLUSIVE);
-
- // Return the formatted string.
- return ipAddressesStringBuilder;
- }
-
- // `onPostExecute()` operates on the UI thread.
- @Override
- protected void onPostExecute(SpannableStringBuilder ipAddresses) {
- // Get handles for the activity and the alert dialog.
- Activity activity = activityWeakReference.get();
- AlertDialog alertDialog = alertDialogWeakReference.get();
-
- // Abort if the activity or the alert dialog is gone.
- if ((activity == null) || (activity.isFinishing()) || (alertDialog == null)) {
- return;
- }
-
- // Get a handle for the IP addresses text view.
- TextView ipAddressesTextView = alertDialog.findViewById(R.id.ip_addresses);
-
- // Populate the IP addresses text view.
- ipAddressesTextView.setText(ipAddresses);
- }
- }
}
\ No newline at end of file
}
// The deprecated `getDrawable()` must be used until the minimum API >= 21.
- @SuppressWarnings("deprecation")
@Override
public View onCreateView(@NonNull LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
// Inflate `domain_settings_fragment`. `false` does not attach it to the root `container`.
View domainSettingsView = inflater.inflate(R.layout.domain_settings_fragment, container, false);
- // Get a handle for the `Context` and the `Resources`.
+ // Get a handle for the context and the resources.
Context context = getContext();
final Resources resources = getResources();
// Get handles for the views in the fragment.
final EditText domainNameEditText = domainSettingsView.findViewById(R.id.domain_settings_name_edittext);
- final Switch javaScriptEnabledSwitch = domainSettingsView.findViewById(R.id.domain_settings_javascript_switch);
- final ImageView javaScriptImageView = domainSettingsView.findViewById(R.id.domain_settings_javascript_imageview);
- Switch firstPartyCookiesEnabledSwitch = domainSettingsView.findViewById(R.id.domain_settings_first_party_cookies_switch);
- final ImageView firstPartyCookiesImageView = domainSettingsView.findViewById(R.id.domain_settings_first_party_cookies_imageview);
- LinearLayout thirdPartyCookiesLinearLayout = domainSettingsView.findViewById(R.id.domain_settings_third_party_cookies_linearlayout);
- final Switch thirdPartyCookiesEnabledSwitch = domainSettingsView.findViewById(R.id.domain_settings_third_party_cookies_switch);
- final ImageView thirdPartyCookiesImageView = domainSettingsView.findViewById(R.id.domain_settings_third_party_cookies_imageview);
- final Switch domStorageEnabledSwitch = domainSettingsView.findViewById(R.id.domain_settings_dom_storage_switch);
- final ImageView domStorageImageView = domainSettingsView.findViewById(R.id.domain_settings_dom_storage_imageview);
- Switch formDataEnabledSwitch = domainSettingsView.findViewById(R.id.domain_settings_form_data_switch); // The form data views can be remove once the minimum API >= 26.
- final ImageView formDataImageView = domainSettingsView.findViewById(R.id.domain_settings_form_data_imageview); // The form data views can be remove once the minimum API >= 26.
- Switch easyListSwitch = domainSettingsView.findViewById(R.id.domain_settings_easylist_switch);
- ImageView easyListImageView = domainSettingsView.findViewById(R.id.domain_settings_easylist_imageview);
- Switch easyPrivacySwitch = domainSettingsView.findViewById(R.id.domain_settings_easyprivacy_switch);
- ImageView easyPrivacyImageView = domainSettingsView.findViewById(R.id.domain_settings_easyprivacy_imageview);
- Switch fanboysAnnoyanceListSwitch = domainSettingsView.findViewById(R.id.domain_settings_fanboys_annoyance_list_switch);
- ImageView fanboysAnnoyanceListImageView = domainSettingsView.findViewById(R.id.domain_settings_fanboys_annoyance_list_imageview);
- Switch fanboysSocialBlockingListSwitch = domainSettingsView.findViewById(R.id.domain_settings_fanboys_social_blocking_list_switch);
- ImageView fanboysSocialBlockingListImageView = domainSettingsView.findViewById(R.id.domain_settings_fanboys_social_blocking_list_imageview);
- Switch ultraPrivacySwitch = domainSettingsView.findViewById(R.id.domain_settings_ultraprivacy_switch);
- ImageView ultraPrivacyImageView = domainSettingsView.findViewById(R.id.domain_settings_ultraprivacy_imageview);
- Switch blockAllThirdPartyRequestsSwitch = domainSettingsView.findViewById(R.id.domain_settings_block_all_third_party_requests_switch);
- ImageView blockAllThirdPartyRequestsImageView = domainSettingsView.findViewById(R.id.domain_settings_block_all_third_party_requests_imageview);
- final Spinner userAgentSpinner = domainSettingsView.findViewById(R.id.domain_settings_user_agent_spinner);
- final TextView userAgentTextView = domainSettingsView.findViewById(R.id.domain_settings_user_agent_textview);
- final EditText customUserAgentEditText = domainSettingsView.findViewById(R.id.domain_settings_custom_user_agent_edittext);
- final Spinner fontSizeSpinner = domainSettingsView.findViewById(R.id.domain_settings_font_size_spinner);
- final TextView fontSizeTextView = domainSettingsView.findViewById(R.id.domain_settings_font_size_textview);
- final ImageView swipeToRefreshImageView = domainSettingsView.findViewById(R.id.domain_settings_swipe_to_refresh_imageview);
- final Spinner swipeToRefreshSpinner = domainSettingsView.findViewById(R.id.domain_settings_swipe_to_refresh_spinner);
- final TextView swipeToRefreshTextView = domainSettingsView.findViewById(R.id.domain_settings_swipe_to_refresh_textview);
- final ImageView nightModeImageView = domainSettingsView.findViewById(R.id.domain_settings_night_mode_imageview);
- final Spinner nightModeSpinner = domainSettingsView.findViewById(R.id.domain_settings_night_mode_spinner);
- final TextView nightModeTextView = domainSettingsView.findViewById(R.id.domain_settings_night_mode_textview);
- final ImageView displayWebpageImagesImageView = domainSettingsView.findViewById(R.id.domain_settings_display_webpage_images_imageview);
- final Spinner displayWebpageImagesSpinner = domainSettingsView.findViewById(R.id.domain_settings_display_webpage_images_spinner);
- final TextView displayImagesTextView = domainSettingsView.findViewById(R.id.domain_settings_display_webpage_images_textview);
- final ImageView pinnedSslCertificateImageView = domainSettingsView.findViewById(R.id.domain_settings_pinned_ssl_certificate_imageview);
- Switch pinnedSslCertificateSwitch = domainSettingsView.findViewById(R.id.domain_settings_pinned_ssl_certificate_switch);
+ final Switch javaScriptEnabledSwitch = domainSettingsView.findViewById(R.id.javascript_switch);
+ final ImageView javaScriptImageView = domainSettingsView.findViewById(R.id.javascript_imageview);
+ Switch firstPartyCookiesEnabledSwitch = domainSettingsView.findViewById(R.id.first_party_cookies_switch);
+ final ImageView firstPartyCookiesImageView = domainSettingsView.findViewById(R.id.first_party_cookies_imageview);
+ LinearLayout thirdPartyCookiesLinearLayout = domainSettingsView.findViewById(R.id.third_party_cookies_linearlayout);
+ final Switch thirdPartyCookiesEnabledSwitch = domainSettingsView.findViewById(R.id.third_party_cookies_switch);
+ final ImageView thirdPartyCookiesImageView = domainSettingsView.findViewById(R.id.third_party_cookies_imageview);
+ final Switch domStorageEnabledSwitch = domainSettingsView.findViewById(R.id.dom_storage_switch);
+ final ImageView domStorageImageView = domainSettingsView.findViewById(R.id.dom_storage_imageview);
+ Switch formDataEnabledSwitch = domainSettingsView.findViewById(R.id.form_data_switch); // The form data views can be remove once the minimum API >= 26.
+ final ImageView formDataImageView = domainSettingsView.findViewById(R.id.form_data_imageview); // The form data views can be remove once the minimum API >= 26.
+ Switch easyListSwitch = domainSettingsView.findViewById(R.id.easylist_switch);
+ ImageView easyListImageView = domainSettingsView.findViewById(R.id.easylist_imageview);
+ Switch easyPrivacySwitch = domainSettingsView.findViewById(R.id.easyprivacy_switch);
+ ImageView easyPrivacyImageView = domainSettingsView.findViewById(R.id.easyprivacy_imageview);
+ Switch fanboysAnnoyanceListSwitch = domainSettingsView.findViewById(R.id.fanboys_annoyance_list_switch);
+ ImageView fanboysAnnoyanceListImageView = domainSettingsView.findViewById(R.id.fanboys_annoyance_list_imageview);
+ Switch fanboysSocialBlockingListSwitch = domainSettingsView.findViewById(R.id.fanboys_social_blocking_list_switch);
+ ImageView fanboysSocialBlockingListImageView = domainSettingsView.findViewById(R.id.fanboys_social_blocking_list_imageview);
+ Switch ultraPrivacySwitch = domainSettingsView.findViewById(R.id.ultraprivacy_switch);
+ ImageView ultraPrivacyImageView = domainSettingsView.findViewById(R.id.ultraprivacy_imageview);
+ Switch blockAllThirdPartyRequestsSwitch = domainSettingsView.findViewById(R.id.block_all_third_party_requests_switch);
+ ImageView blockAllThirdPartyRequestsImageView = domainSettingsView.findViewById(R.id.block_all_third_party_requests_imageview);
+ final Spinner userAgentSpinner = domainSettingsView.findViewById(R.id.user_agent_spinner);
+ final TextView userAgentTextView = domainSettingsView.findViewById(R.id.user_agent_textview);
+ final EditText customUserAgentEditText = domainSettingsView.findViewById(R.id.custom_user_agent_edittext);
+ final Spinner fontSizeSpinner = domainSettingsView.findViewById(R.id.font_size_spinner);
+ final TextView fontSizeTextView = domainSettingsView.findViewById(R.id.font_size_textview);
+ final ImageView swipeToRefreshImageView = domainSettingsView.findViewById(R.id.swipe_to_refresh_imageview);
+ final Spinner swipeToRefreshSpinner = domainSettingsView.findViewById(R.id.swipe_to_refresh_spinner);
+ final TextView swipeToRefreshTextView = domainSettingsView.findViewById(R.id.swipe_to_refresh_textview);
+ final ImageView nightModeImageView = domainSettingsView.findViewById(R.id.night_mode_imageview);
+ final Spinner nightModeSpinner = domainSettingsView.findViewById(R.id.night_mode_spinner);
+ final TextView nightModeTextView = domainSettingsView.findViewById(R.id.night_mode_textview);
+ final ImageView displayWebpageImagesImageView = domainSettingsView.findViewById(R.id.display_webpage_images_imageview);
+ final Spinner displayWebpageImagesSpinner = domainSettingsView.findViewById(R.id.display_webpage_images_spinner);
+ final TextView displayImagesTextView = domainSettingsView.findViewById(R.id.display_webpage_images_textview);
+ final ImageView pinnedSslCertificateImageView = domainSettingsView.findViewById(R.id.pinned_ssl_certificate_imageview);
+ Switch pinnedSslCertificateSwitch = domainSettingsView.findViewById(R.id.pinned_ssl_certificate_switch);
final CardView savedSslCertificateCardView = domainSettingsView.findViewById(R.id.saved_ssl_certificate_cardview);
LinearLayout savedSslCertificateLinearLayout = domainSettingsView.findViewById(R.id.saved_ssl_certificate_linearlayout);
final RadioButton savedSslCertificateRadioButton = domainSettingsView.findViewById(R.id.saved_ssl_certificate_radiobutton);
TextView currentWebsiteCertificateStartDateTextView = domainSettingsView.findViewById(R.id.current_website_certificate_start_date);
TextView currentWebsiteCertificateEndDateTextView = domainSettingsView.findViewById(R.id.current_website_certificate_end_date);
final TextView noCurrentWebsiteCertificateTextView = domainSettingsView.findViewById(R.id.no_current_website_certificate);
-
- // Setup the SSL certificate labels.
- final String cNameLabel = getString(R.string.common_name) + " ";
+ ImageView pinnedIpAddressesImageView = domainSettingsView.findViewById(R.id.pinned_ip_addresses_imageview);
+ Switch pinnedIpAddressesSwitch = domainSettingsView.findViewById(R.id.pinned_ip_addresses_switch);
+ CardView savedIpAddressesCardView = domainSettingsView.findViewById(R.id.saved_ip_addresses_cardview);
+ LinearLayout savedIpAddressesLinearLayout = domainSettingsView.findViewById(R.id.saved_ip_addresses_linearlayout);
+ RadioButton savedIpAddressesRadioButton = domainSettingsView.findViewById(R.id.saved_ip_addresses_radiobutton);
+ TextView savedIpAddressesTextView = domainSettingsView.findViewById(R.id.saved_ip_addresses_textview);
+ CardView currentIpAddressesCardView = domainSettingsView.findViewById(R.id.current_ip_addresses_cardview);
+ LinearLayout currentIpAddressesLinearLayout = domainSettingsView.findViewById(R.id.current_ip_addresses_linearlayout);
+ RadioButton currentIpAddressesRadioButton = domainSettingsView.findViewById(R.id.current_ip_addresses_radiobutton);
+ TextView currentIpAddressesTextView = domainSettingsView.findViewById(R.id.current_ip_addresses_textview);
+
+ // Setup the pinned labels.
+ String cNameLabel = getString(R.string.common_name) + " ";
String oNameLabel = getString(R.string.organization) + " ";
String uNameLabel = getString(R.string.organizational_unit) + " ";
String startDateLabel = getString(R.string.start_date) + " ";
// Initialize the database handler. The `0` specifies the database version, but that is ignored and set instead using a constant in `DomainsDatabaseHelper`.
DomainsDatabaseHelper domainsDatabaseHelper = new DomainsDatabaseHelper(context, null, null, 0);
- // Get the database `Cursor` for this ID and move it to the first row.
+ // Get the database cursor for this ID and move it to the first row.
Cursor domainCursor = domainsDatabaseHelper.getCursorForId(databaseId);
domainCursor.moveToFirst();
- // Save the `Cursor` entries as variables.
+ // Save the cursor entries as variables.
String domainNameString = domainCursor.getString(domainCursor.getColumnIndex(DomainsDatabaseHelper.DOMAIN_NAME));
final int javaScriptEnabledInt = domainCursor.getInt(domainCursor.getColumnIndex(DomainsDatabaseHelper.ENABLE_JAVASCRIPT));
int firstPartyCookiesEnabledInt = domainCursor.getInt(domainCursor.getColumnIndex(DomainsDatabaseHelper.ENABLE_FIRST_PARTY_COOKIES));
int nightModeInt = domainCursor.getInt(domainCursor.getColumnIndex(DomainsDatabaseHelper.NIGHT_MODE));
int displayImagesInt = domainCursor.getInt(domainCursor.getColumnIndex(DomainsDatabaseHelper.DISPLAY_IMAGES));
int pinnedSslCertificateInt = domainCursor.getInt(domainCursor.getColumnIndex(DomainsDatabaseHelper.PINNED_SSL_CERTIFICATE));
- final String savedSslCertificateIssuedToCNameString = domainCursor.getString(domainCursor.getColumnIndex(DomainsDatabaseHelper.SSL_ISSUED_TO_COMMON_NAME));
+ String savedSslCertificateIssuedToCNameString = domainCursor.getString(domainCursor.getColumnIndex(DomainsDatabaseHelper.SSL_ISSUED_TO_COMMON_NAME));
String savedSslCertificateIssuedToONameString = domainCursor.getString(domainCursor.getColumnIndex(DomainsDatabaseHelper.SSL_ISSUED_TO_ORGANIZATION));
String savedSslCertificateIssuedToUNameString = domainCursor.getString(domainCursor.getColumnIndex(DomainsDatabaseHelper.SSL_ISSUED_TO_ORGANIZATIONAL_UNIT));
String savedSslCertificateIssuedByCNameString = domainCursor.getString(domainCursor.getColumnIndex(DomainsDatabaseHelper.SSL_ISSUED_BY_COMMON_NAME));
String savedSslCertificateIssuedByONameString = domainCursor.getString(domainCursor.getColumnIndex(DomainsDatabaseHelper.SSL_ISSUED_BY_ORGANIZATION));
String savedSslCertificateIssuedByUNameString = domainCursor.getString(domainCursor.getColumnIndex(DomainsDatabaseHelper.SSL_ISSUED_BY_ORGANIZATIONAL_UNIT));
+ int pinnedIpAddressesInt = domainCursor.getInt(domainCursor.getColumnIndex(DomainsDatabaseHelper.PINNED_IP_ADDRESSES));
+ String savedIpAddresses = domainCursor.getString(domainCursor.getColumnIndex(DomainsDatabaseHelper.IP_ADDRESSES));
// Initialize the saved SSL certificate date variables.
Date savedSslCertificateStartDate = null;
SpannableStringBuilder savedSslCertificateIssuedByONameStringBuilder = new SpannableStringBuilder(oNameLabel + savedSslCertificateIssuedByONameString);
SpannableStringBuilder savedSslCertificateIssuedByUNameStringBuilder = new SpannableStringBuilder(uNameLabel + savedSslCertificateIssuedByUNameString);
- // Initialize the `SpannableStringBuilders` for the SSL certificate dates.
+ // Initialize the spannable string builders for the SSL certificate dates.
SpannableStringBuilder savedSslCertificateStartDateStringBuilder;
SpannableStringBuilder savedSslCertificateEndDateStringBuilder;
savedSslCertificateEndDateStringBuilder = new SpannableStringBuilder(endDateLabel + DateFormat.getDateTimeInstance(DateFormat.MEDIUM, DateFormat.LONG).format(savedSslCertificateEndDate));
}
- // Create a red `ForegroundColorSpan`. We have to use the deprecated `getColor` until API >= 23.
- final ForegroundColorSpan redColorSpan = new ForegroundColorSpan(getResources().getColor(R.color.red_a700));
+ // Create a red foreground color span. The deprecated `resources.getColor` must be used until the minimum API >= 23.
+ final ForegroundColorSpan redColorSpan = new ForegroundColorSpan(resources.getColor(R.color.red_a700));
- // Create a blue `ForegroundColorSpan`.
+ // Create a blue foreground color span.
final ForegroundColorSpan blueColorSpan;
- // Set `blueColorSpan` according to the theme. We have to use the deprecated `getColor()` until API >= 23.
+ // Set the blue color span according to the theme. The deprecated `resources.getColor` must be used until the minimum API >= 23.
if (MainWebViewActivity.darkTheme) {
//noinspection deprecation
- blueColorSpan = new ForegroundColorSpan(getResources().getColor(R.color.blue_400));
+ blueColorSpan = new ForegroundColorSpan(resources.getColor(R.color.blue_400));
} else {
//noinspection deprecation
- blueColorSpan = new ForegroundColorSpan(getResources().getColor(R.color.blue_700));
+ blueColorSpan = new ForegroundColorSpan(resources.getColor(R.color.blue_700));
}
// Set the domain name from the the database cursor.
}
});
- // Create a `boolean` to track if night mode is enabled.
+ // Create a boolean to track if night mode is enabled.
boolean nightModeEnabled = (nightModeInt == DomainsDatabaseHelper.NIGHT_MODE_ENABLED) || ((nightModeInt == DomainsDatabaseHelper.NIGHT_MODE_SYSTEM_DEFAULT) && defaultNightMode);
// Disable the JavaScript switch if night mode is enabled.
// Store the current date.
Date currentDate = Calendar.getInstance().getTime();
- // Setup the `StringBuilders` to display the general certificate information in blue. `SPAN_INCLUSIVE_INCLUSIVE` allows the span to grow in either direction.
+ // Setup the string builders to display the general certificate information in blue. `SPAN_INCLUSIVE_INCLUSIVE` allows the span to grow in either direction.
savedSslCertificateIssuedToONameStringBuilder.setSpan(blueColorSpan, oNameLabel.length(), savedSslCertificateIssuedToONameStringBuilder.length(), Spanned.SPAN_INCLUSIVE_INCLUSIVE);
savedSslCertificateIssuedToUNameStringBuilder.setSpan(blueColorSpan, uNameLabel.length(), savedSslCertificateIssuedToUNameStringBuilder.length(), Spanned.SPAN_INCLUSIVE_INCLUSIVE);
savedSslCertificateIssuedByCNameStringBuilder.setSpan(blueColorSpan, cNameLabel.length(), savedSslCertificateIssuedByCNameStringBuilder.length(), Spanned.SPAN_INCLUSIVE_INCLUSIVE);
savedSslCertificateIssuedByONameStringBuilder.setSpan(blueColorSpan, oNameLabel.length(), savedSslCertificateIssuedByONameStringBuilder.length(), Spanned.SPAN_INCLUSIVE_INCLUSIVE);
savedSslCertificateIssuedByUNameStringBuilder.setSpan(blueColorSpan, uNameLabel.length(), savedSslCertificateIssuedByUNameStringBuilder.length(), Spanned.SPAN_INCLUSIVE_INCLUSIVE);
- // Check the certificate `Common Name` against the domain name.
+ // Check the certificate Common Name against the domain name.
boolean savedSSlCertificateCommonNameMatchesDomainName = checkDomainNameAgainstCertificate(domainNameString, savedSslCertificateIssuedToCNameString);
- // Format the `issuedToCommonName` color. `SPAN_INCLUSIVE_INCLUSIVE` allows the span to grow in either direction.
+ // Format the issued to Common Name color. `SPAN_INCLUSIVE_INCLUSIVE` allows the span to grow in either direction.
if (savedSSlCertificateCommonNameMatchesDomainName) {
savedSslCertificateIssuedToCNameStringBuilder.setSpan(blueColorSpan, cNameLabel.length(), savedSslCertificateIssuedToCNameStringBuilder.length(), Spanned.SPAN_INCLUSIVE_INCLUSIVE);
} else {
savedSslCertificateEndDateStringBuilder.setSpan(blueColorSpan, endDateLabel.length(), savedSslCertificateEndDateStringBuilder.length(), Spanned.SPAN_INCLUSIVE_INCLUSIVE);
}
- // Display the current website SSL certificate strings.
+ // Display the saved website SSL certificate strings.
savedSslCertificateIssuedToCNameTextView.setText(savedSslCertificateIssuedToCNameStringBuilder);
savedSslCertificateIssuedToONameTextView.setText(savedSslCertificateIssuedToONameStringBuilder);
savedSslCertificateIssuedToUNameTextView.setText(savedSslCertificateIssuedToUNameStringBuilder);
Date currentWebsiteCertificateStartDate = currentWebsiteSslCertificate.getValidNotBeforeDate();
Date currentWebsiteCertificateEndDate = currentWebsiteSslCertificate.getValidNotAfterDate();
- // Create a `SpannableStringBuilder` for each `TextView` that needs multiple colors of text.
+ // Create a spannable string builder for each text view that needs multiple colors of text.
SpannableStringBuilder currentWebsiteCertificateIssuedToCNameStringBuilder = new SpannableStringBuilder(cNameLabel + currentWebsiteCertificateIssuedToCNameString);
SpannableStringBuilder currentWebsiteCertificateIssuedToONameStringBuilder = new SpannableStringBuilder(oNameLabel + currentWebsiteCertificateIssuedToONameString);
SpannableStringBuilder currentWebsiteCertificateIssuedToUNameStringBuilder = new SpannableStringBuilder(uNameLabel + currentWebsiteCertificateIssuedToUNameString);
SpannableStringBuilder currentWebsiteCertificateEndDateStringBuilder = new SpannableStringBuilder(endDateLabel + DateFormat.getDateTimeInstance(DateFormat.MEDIUM, DateFormat.LONG)
.format(currentWebsiteCertificateEndDate));
- // Setup the `StringBuilders` to display the general certificate information in blue. `SPAN_INCLUSIVE_INCLUSIVE` allows the span to grow in either direction.
+ // Setup the string builders to display the general certificate information in blue. `SPAN_INCLUSIVE_INCLUSIVE` allows the span to grow in either direction.
currentWebsiteCertificateIssuedToONameStringBuilder.setSpan(blueColorSpan, oNameLabel.length(), currentWebsiteCertificateIssuedToONameStringBuilder.length(), Spanned.SPAN_INCLUSIVE_INCLUSIVE);
currentWebsiteCertificateIssuedToUNameStringBuilder.setSpan(blueColorSpan, uNameLabel.length(), currentWebsiteCertificateIssuedToUNameStringBuilder.length(), Spanned.SPAN_INCLUSIVE_INCLUSIVE);
currentWebsiteCertificateIssuedByCNameStringBuilder.setSpan(blueColorSpan, cNameLabel.length(), currentWebsiteCertificateIssuedByCNameStringBuilder.length(), Spanned.SPAN_INCLUSIVE_INCLUSIVE);
currentWebsiteCertificateIssuedByONameStringBuilder.setSpan(blueColorSpan, oNameLabel.length(), currentWebsiteCertificateIssuedByONameStringBuilder.length(), Spanned.SPAN_INCLUSIVE_INCLUSIVE);
currentWebsiteCertificateIssuedByUNameStringBuilder.setSpan(blueColorSpan, uNameLabel.length(), currentWebsiteCertificateIssuedByUNameStringBuilder.length(), Spanned.SPAN_INCLUSIVE_INCLUSIVE);
- // Check the certificate `Common Name` against the domain name.
+ // Check the certificate Common Name against the domain name.
boolean currentWebsiteCertificateCommonNameMatchesDomainName = checkDomainNameAgainstCertificate(domainNameString, currentWebsiteCertificateIssuedToCNameString);
- // Format the `issuedToCommonName` color. `SPAN_INCLUSIVE_INCLUSIVE` allows the span to grow in either direction.
+ // Format the issued to Common Name color. `SPAN_INCLUSIVE_INCLUSIVE` allows the span to grow in either direction.
if (currentWebsiteCertificateCommonNameMatchesDomainName) {
currentWebsiteCertificateIssuedToCNameStringBuilder.setSpan(blueColorSpan, cNameLabel.length(), currentWebsiteCertificateIssuedToCNameStringBuilder.length(), Spanned.SPAN_INCLUSIVE_INCLUSIVE);
} else {
currentWebsiteCertificateEndDateTextView.setText(currentWebsiteCertificateEndDateStringBuilder);
}
- // Set the initial display status for the SSL certificates.
- if (pinnedSslCertificateSwitch.isChecked()) {
+ // Set the initial display status of the SSL certificates card views.
+ if (pinnedSslCertificateSwitch.isChecked()) { // An SSL certificate is pinned.
// Set the visibility of the saved SSL certificate.
if (savedSslCertificateIssuedToCNameString == null) {
savedSslCertificateCardView.setVisibility(View.GONE);
}
// Set the visibility of the current website SSL certificate.
- if (currentWebsiteSslCertificate == null) {
+ if (currentWebsiteSslCertificate == null) { // There is no current SSL certificate.
// Hide the SSL certificate.
currentWebsiteCertificateCardView.setVisibility(View.GONE);
// Show the instruction.
noCurrentWebsiteCertificateTextView.setVisibility(View.VISIBLE);
- } else {
+ } else { // There is a current SSL certificate.
// Show the SSL certificate.
currentWebsiteCertificateCardView.setVisibility(View.VISIBLE);
noCurrentWebsiteCertificateTextView.setVisibility(View.GONE);
}
- // Set the status of the radio buttons.
+ // Set the status of the radio buttons and the card view backgrounds.
if (savedSslCertificateCardView.getVisibility() == View.VISIBLE) { // The saved SSL certificate is displayed.
// Check the saved SSL certificate radio button.
savedSslCertificateRadioButton.setChecked(true);
// Uncheck the saved SSL certificate radio button.
savedSslCertificateRadioButton.setChecked(false);
-
- // Darken the background of the saved SSL certificate linear layout according to the theme.
- if (MainWebViewActivity.darkTheme) {
- savedSslCertificateLinearLayout.setBackgroundResource(R.color.black_translucent_33);
- } else {
- savedSslCertificateLinearLayout.setBackgroundResource(R.color.black_translucent_11);
- }
} else { // Neither SSL certificate is visible.
// Uncheck both radio buttons.
savedSslCertificateRadioButton.setChecked(false);
currentWebsiteCertificateRadioButton.setChecked(false);
}
- } else { // `pinnedSslCertificateSwitch` is not checked.
+ } else { // An SSL certificate is not pinned.
// Hide the SSl certificates and instructions.
savedSslCertificateCardView.setVisibility(View.GONE);
currentWebsiteCertificateCardView.setVisibility(View.GONE);
currentWebsiteCertificateRadioButton.setChecked(false);
}
+ // Set the pinned IP addresses icon.
+ if (pinnedIpAddressesInt == 1) { // Pinned IP addresses is enabled. Once the minimum API >= 21 a selector can be sued as the tint mode instead of specifying different icons.
+ // Check the switch.
+ pinnedIpAddressesSwitch.setChecked(true);
+
+ // Set the icon according to the theme.
+ if (MainWebViewActivity.darkTheme) {
+ pinnedIpAddressesImageView.setImageDrawable(resources.getDrawable(R.drawable.ssl_certificate_enabled_dark));
+ } else {
+ pinnedIpAddressesImageView.setImageDrawable(resources.getDrawable(R.drawable.ssl_certificate_enabled_light));
+ }
+ } else { // Pinned IP Addresses is disabled.
+ // Uncheck the switch.
+ pinnedIpAddressesSwitch.setChecked(false);
+
+ // Set the icon according to the theme.
+ if (MainWebViewActivity.darkTheme) {
+ pinnedIpAddressesImageView.setImageDrawable(resources.getDrawable(R.drawable.ssl_certificate_disabled_dark));
+ } else {
+ pinnedIpAddressesImageView.setImageDrawable(resources.getDrawable(R.drawable.ssl_certificate_disabled_light));
+ }
+ }
+
+ // Populate the saved and current IP addresses.
+ savedIpAddressesTextView.setText(savedIpAddresses);
+ currentIpAddressesTextView.setText(MainWebViewActivity.currentHostIpAddresses);
+
+ // Set the initial display status of the IP addresses card views.
+ if (pinnedIpAddressesSwitch.isChecked()) { // IP addresses are pinned.
+ // Set the visibility of the saved IP addresses.
+ if (savedIpAddresses == null) { // There are no saved IP addresses.
+ savedIpAddressesCardView.setVisibility(View.GONE);
+ } else { // There are saved IP addresses.
+ savedIpAddressesCardView.setVisibility(View.VISIBLE);
+ }
+
+ // Set the visibility of the current IP addresses.
+ currentIpAddressesCardView.setVisibility(View.VISIBLE);
+
+ // Set the status of the radio buttons and the card view backgrounds.
+ if (savedIpAddressesCardView.getVisibility() == View.VISIBLE) { // The saved IP addresses are displayed.
+ // Check the saved IP addresses radio button.
+ savedIpAddressesRadioButton.setChecked(true);
+
+ // Uncheck the current IP addresses radio button.
+ currentIpAddressesRadioButton.setChecked(false);
+
+ // Darken the background of the current IP addresses linear layout according to the theme.
+ if (MainWebViewActivity.darkTheme) {
+ currentIpAddressesLinearLayout.setBackgroundResource(R.color.black_translucent_33);
+ } else {
+ currentIpAddressesLinearLayout.setBackgroundResource(R.color.black_translucent_11);
+ }
+ } else { // The saved IP addresses are hidden.
+ // Check the current IP addresses radio button.
+ currentIpAddressesRadioButton.setChecked(true);
+
+ // Uncheck the saved IP addresses radio button.
+ savedIpAddressesRadioButton.setChecked(false);
+ }
+ } else { // IP addresses are not pinned.
+ // Hide the IP addresses card views.
+ savedIpAddressesCardView.setVisibility(View.GONE);
+ currentIpAddressesCardView.setVisibility(View.GONE);
+
+ // Uncheck the radio buttons.
+ savedIpAddressesRadioButton.setChecked(false);
+ currentIpAddressesRadioButton.setChecked(false);
+ }
+
// Set the JavaScript switch listener.
javaScriptEnabledSwitch.setOnCheckedChangeListener((CompoundButton buttonView, boolean isChecked) -> {
// Set the pinned SSL certificate switch listener.
pinnedSslCertificateSwitch.setOnCheckedChangeListener((CompoundButton buttonView, boolean isChecked) -> {
- // Update the icon
- if (isChecked) { // Pinned SSL certificate is enabled.
+ // Update the icon.
+ if (isChecked) { // SSL certificate pinning is enabled.
// Set the icon according to the theme.
if (MainWebViewActivity.darkTheme) {
pinnedSslCertificateImageView.setImageDrawable(resources.getDrawable(R.drawable.ssl_certificate_enabled_dark));
} else {
currentWebsiteCertificateLinearLayout.setBackgroundResource(R.color.black_translucent_11);
}
+
+ // Scroll to the current website SSL certificate card.
+ savedSslCertificateCardView.getParent().requestChildFocus(savedSslCertificateCardView, savedSslCertificateCardView);
} else if (currentWebsiteCertificateCardView.getVisibility() == View.VISIBLE) { // The saved SSL certificate is hidden but the current website SSL certificate is visible.
// Check the current website SSL certificate radio button.
currentWebsiteCertificateRadioButton.setChecked(true);
} else {
savedSslCertificateLinearLayout.setBackgroundResource(R.color.black_translucent_11);
}
+
+ // Scroll to the current website SSL certificate card.
+ currentWebsiteCertificateCardView.getParent().requestChildFocus(currentWebsiteCertificateCardView, currentWebsiteCertificateCardView);
} else { // Neither SSL certificate is visible.
// Uncheck both radio buttons.
savedSslCertificateRadioButton.setChecked(false);
currentWebsiteCertificateRadioButton.setChecked(false);
+
+ // Scroll to the current website SSL certificate card.
+ noCurrentWebsiteCertificateTextView.getParent().requestChildFocus(noCurrentWebsiteCertificateTextView, noCurrentWebsiteCertificateTextView);
}
- } else { // Pinned SSL certificate is disabled.
+ } else { // SSL certificate pinning is disabled.
// Set the icon according to the theme.
if (MainWebViewActivity.darkTheme) {
pinnedSslCertificateImageView.setImageDrawable(resources.getDrawable(R.drawable.ssl_certificate_disabled_dark));
}
});
- savedSslCertificateCardView.setOnClickListener((View v) -> {
+ savedSslCertificateCardView.setOnClickListener((View view) -> {
// Check the saved SSL certificate radio button.
savedSslCertificateRadioButton.setChecked(true);
}
});
- savedSslCertificateRadioButton.setOnClickListener((View v) -> {
+ savedSslCertificateRadioButton.setOnClickListener((View view) -> {
// Check the saved SSL certificate radio button.
savedSslCertificateRadioButton.setChecked(true);
}
});
- currentWebsiteCertificateCardView.setOnClickListener((View v) -> {
+ currentWebsiteCertificateCardView.setOnClickListener((View view) -> {
// Check the current website SSL certificate radio button.
currentWebsiteCertificateRadioButton.setChecked(true);
}
});
- currentWebsiteCertificateRadioButton.setOnClickListener((View v) -> {
+ currentWebsiteCertificateRadioButton.setOnClickListener((View view) -> {
// Check the current website SSL certificate radio button.
currentWebsiteCertificateRadioButton.setChecked(true);
}
});
+ // Set the pinned IP addresses switch listener.
+ pinnedIpAddressesSwitch.setOnCheckedChangeListener((CompoundButton buttonView, boolean isChecked) -> {
+ // Update the icon.
+ if (isChecked) { // IP addresses pinning is enabled.
+ // Set the icon according to the theme.
+ if (MainWebViewActivity.darkTheme) {
+ pinnedIpAddressesImageView.setImageDrawable(resources.getDrawable(R.drawable.ssl_certificate_enabled_dark));
+ } else {
+ pinnedIpAddressesImageView.setImageDrawable(resources.getDrawable(R.drawable.ssl_certificate_enabled_light));
+ }
+
+ // Update the visibility of the saved IP addresses card view.
+ if (savedIpAddresses == null) { // There are no saved IP addresses.
+ savedIpAddressesCardView.setVisibility(View.GONE);
+ } else { // There are saved IP addresses.
+ savedIpAddressesCardView.setVisibility(View.VISIBLE);
+ }
+
+ // Show the current IP addresses card view.
+ currentIpAddressesCardView.setVisibility(View.VISIBLE);
+
+ // Set the status of the radio buttons.
+ if (savedIpAddressesCardView.getVisibility() == View.VISIBLE) { // The saved IP addresses are visible.
+ // Check the saved IP addresses radio button.
+ savedIpAddressesRadioButton.setChecked(true);
+
+ // Uncheck the current IP addresses radio button.
+ currentIpAddressesRadioButton.setChecked(false);
+
+ // Set the background of the saved IP addresses linear layout to be transparent.
+ savedSslCertificateLinearLayout.setBackgroundResource(R.color.transparent);
+
+ // Darken the background of the current IP addresses linear layout according to the theme.
+ if (MainWebViewActivity.darkTheme) {
+ currentIpAddressesLinearLayout.setBackgroundResource(R.color.black_translucent_33);
+ } else {
+ currentIpAddressesLinearLayout.setBackgroundResource(R.color.black_translucent_11);
+ }
+ } else { // The saved IP addresses are not visible.
+ // Check the current IP addresses radio button.
+ currentIpAddressesRadioButton.setChecked(true);
+
+ // Uncheck the saved IP addresses radio button.
+ savedIpAddressesRadioButton.setChecked(false);
+
+ // Set the background of the current IP addresses linear layout to be transparent.
+ currentIpAddressesLinearLayout.setBackgroundResource(R.color.transparent);
+
+ // Darken the background of the saved IP addresses linear layout according to the theme.
+ if (MainWebViewActivity.darkTheme) {
+ savedIpAddressesLinearLayout.setBackgroundResource(R.color.black_translucent_33);
+ } else {
+ savedIpAddressesLinearLayout.setBackgroundResource(R.color.black_translucent_11);
+ }
+ }
+
+ // Scroll to the bottom of the card views.
+ currentIpAddressesCardView.getParent().requestChildFocus(currentIpAddressesCardView, currentIpAddressesCardView);
+ } else { // IP addresses pinning is disabled.
+ // Set the icon according to the theme.
+ if (MainWebViewActivity.darkTheme) {
+ pinnedIpAddressesImageView.setImageDrawable(resources.getDrawable(R.drawable.ssl_certificate_disabled_dark));
+ } else {
+ pinnedIpAddressesImageView.setImageDrawable(resources.getDrawable(R.drawable.ssl_certificate_disabled_light));
+ }
+
+ // Hide the IP addresses card views.
+ savedIpAddressesCardView.setVisibility(View.GONE);
+ currentIpAddressesCardView.setVisibility(View.GONE);
+
+ // Uncheck the radio buttons.
+ savedIpAddressesRadioButton.setChecked(false);
+ currentIpAddressesRadioButton.setChecked(false);
+ }
+ });
+
+ savedIpAddressesCardView.setOnClickListener((View view) -> {
+ // Check the saved IP addresses radio button.
+ savedIpAddressesRadioButton.setChecked(true);
+
+ // Uncheck the current website IP addresses radio button.
+ currentIpAddressesRadioButton.setChecked(false);
+
+ // Set the background of the saved IP addresses linear layout to be transparent.
+ savedIpAddressesLinearLayout.setBackgroundResource(R.color.transparent);
+
+ // Darken the background of the current IP addresses linear layout according to the theme.
+ if (MainWebViewActivity.darkTheme) {
+ currentIpAddressesLinearLayout.setBackgroundResource(R.color.black_translucent_33);
+ } else {
+ currentIpAddressesLinearLayout.setBackgroundResource(R.color.black_translucent_11);
+ }
+ });
+
+ savedIpAddressesRadioButton.setOnClickListener((View view) -> {
+ // Check the saved IP addresses radio button.
+ savedIpAddressesRadioButton.setChecked(true);
+
+ // Uncheck the current website IP addresses radio button.
+ currentIpAddressesRadioButton.setChecked(false);
+
+ // Set the background of the saved IP addresses linear layout to be transparent.
+ savedIpAddressesLinearLayout.setBackgroundResource(R.color.transparent);
+
+ // Darken the background of the current IP addresses linear layout according to the theme.
+ if (MainWebViewActivity.darkTheme) {
+ currentIpAddressesLinearLayout.setBackgroundResource(R.color.black_translucent_33);
+ } else {
+ currentIpAddressesLinearLayout.setBackgroundResource(R.color.black_translucent_11);
+ }
+ });
+
+ currentIpAddressesCardView.setOnClickListener((View view) -> {
+ // Check the current IP addresses radio button.
+ currentIpAddressesRadioButton.setChecked(true);
+
+ // Uncheck the saved IP addresses radio button.
+ savedIpAddressesRadioButton.setChecked(false);
+
+ // Set the background of the current IP addresses linear layout to be transparent.
+ currentIpAddressesLinearLayout.setBackgroundResource(R.color.transparent);
+
+ // Darken the background of the saved IP addresses linear layout according to the theme.
+ if (MainWebViewActivity.darkTheme) {
+ savedIpAddressesLinearLayout.setBackgroundResource(R.color.black_translucent_33);
+ } else {
+ savedIpAddressesLinearLayout.setBackgroundResource(R.color.black_translucent_11);
+ }
+ });
+
+ currentIpAddressesRadioButton.setOnClickListener((View view) -> {
+ // Check the current IP addresses radio button.
+ currentIpAddressesRadioButton.setChecked(true);
+
+ // Uncheck the saved IP addresses radio button.
+ savedIpAddressesRadioButton.setChecked(false);
+
+ // Set the background of the current IP addresses linear layout to be transparent.
+ currentIpAddressesLinearLayout.setBackgroundResource(R.color.transparent);
+
+ // Darken the background of the saved IP addresses linear layout according to the theme.
+ if (MainWebViewActivity.darkTheme) {
+ savedIpAddressesLinearLayout.setBackgroundResource(R.color.black_translucent_33);
+ } else {
+ savedIpAddressesLinearLayout.setBackgroundResource(R.color.black_translucent_11);
+ }
+ });
+
return domainSettingsView;
}
/*
- * 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>.
*
import android.preference.PreferenceManager;
public class DomainsDatabaseHelper extends SQLiteOpenHelper {
- private static final int SCHEMA_VERSION = 8;
+ private static final int SCHEMA_VERSION = 9;
static final String DOMAINS_DATABASE = "domains.db";
static final String DOMAINS_TABLE = "domains";
public static final String SSL_ISSUED_BY_ORGANIZATIONAL_UNIT = "sslissuedbyorganizationalunit";
public static final String SSL_START_DATE = "sslstartdate";
public static final String SSL_END_DATE = "sslenddate";
+ public static final String PINNED_IP_ADDRESSES = "pinned_ip_addresses";
+ public static final String IP_ADDRESSES = "ip_addresses";
// Swipe to refresh constants.
public static final int SWIPE_TO_REFRESH_SYSTEM_DEFAULT = 0;
SSL_ISSUED_BY_ORGANIZATION + " TEXT, " +
SSL_ISSUED_BY_ORGANIZATIONAL_UNIT + " TEXT, " +
SSL_START_DATE + " INTEGER, " +
- SSL_END_DATE + " INTEGER)";
+ SSL_END_DATE + " INTEGER, " +
+ PINNED_IP_ADDRESSES + " BOOLEAN, " +
+ IP_ADDRESSES + " TEXT)";
private final Context appContext;
// Enable it for all existing rows.
domainsDatabase.execSQL("UPDATE " + DOMAINS_TABLE + " SET " + ENABLE_ULTRAPRIVACY + " = " + 1);
+
+ // Upgrade from schema version 8.
+ case 8:
+ // Add the Pinned IP Addresses columns.
+ domainsDatabase.execSQL("ALTER TABLE " + DOMAINS_TABLE + " ADD COLUMN " + PINNED_IP_ADDRESSES + " BOOLEAN");
+ domainsDatabase.execSQL("ALTER TABLE " + DOMAINS_TABLE + " ADD COLUMN " + IP_ADDRESSES + " TEXT");
}
}
domainsDatabase.close();
}
- public void updateDomainExceptCertificate(int databaseId, String domainName, boolean javaScriptEnabled, boolean firstPartyCookiesEnabled, boolean thirdPartyCookiesEnabled, boolean domStorageEnabled,
- boolean formDataEnabled, boolean easyListEnabled, boolean easyPrivacyEnabled, boolean fanboysAnnoyanceEnabled, boolean fanboysSocialBlockingEnabled,
- boolean ultraPrivacyEnabled, boolean blockAllThirdPartyRequests, String userAgent, int fontSize, int swipeToRefresh, int nightMode, int displayImages,
- boolean pinnedSslCertificate) {
+ public void updateDomain(int databaseId, String domainName, boolean javaScriptEnabled, boolean firstPartyCookiesEnabled, boolean thirdPartyCookiesEnabled, boolean domStorageEnabled, boolean formDataEnabled,
+ boolean easyListEnabled, boolean easyPrivacyEnabled, boolean fanboysAnnoyanceEnabled, boolean fanboysSocialBlockingEnabled, boolean ultraPrivacyEnabled,
+ boolean blockAllThirdPartyRequests, String userAgent, int fontSize, int swipeToRefresh, int nightMode, int displayImages, boolean pinnedSslCertificate, boolean pinnedIpAddresses) {
// Store the domain data in a `ContentValues`.
ContentValues domainContentValues = new ContentValues();
domainContentValues.put(NIGHT_MODE, nightMode);
domainContentValues.put(DISPLAY_IMAGES, displayImages);
domainContentValues.put(PINNED_SSL_CERTIFICATE, pinnedSslCertificate);
+ domainContentValues.put(PINNED_IP_ADDRESSES, pinnedIpAddresses);
// Get a writable database handle.
SQLiteDatabase domainsDatabase = this.getWritableDatabase();
domainsDatabase.close();
}
- public void updateDomainWithCertificate(int databaseId, String domainName, boolean javaScriptEnabled, boolean firstPartyCookiesEnabled, boolean thirdPartyCookiesEnabled, boolean domStorageEnabled,
- boolean formDataEnabled, boolean easyListEnabled, boolean easyPrivacyEnabled, boolean fanboysAnnoyanceEnabled, boolean fanboysSocialBlockingEnabled,
- boolean ultraPrivacyEnabled, boolean blockAllThirdPartyRequests, String userAgent, int fontSize, int swipeToRefresh, int nightMode, int displayImages,
- boolean pinnedSslCertificate, String sslIssuedToCommonName, String sslIssuedToOrganization, String sslIssuedToOrganizationalUnit, String sslIssuedByCommonName,
- String sslIssuedByOrganization, String sslIssuedByOrganizationalUnit, long sslStartDate, long sslEndDate) {
+ public void updatePinnedSslCertificate(int databaseId, String sslIssuedToCommonName, String sslIssuedToOrganization, String sslIssuedToOrganizationalUnit, String sslIssuedByCommonName,
+ String sslIssuedByOrganization, String sslIssuedByOrganizationalUnit, long sslStartDate, long sslEndDate) {
- // Store the domain data in a `ContentValues`.
- ContentValues domainContentValues = new ContentValues();
+ // Store the pinned SSL certificate in a content values.
+ ContentValues pinnedSslCertificateContentValues = new ContentValues();
- // Add entries for each field in the database.
- domainContentValues.put(DOMAIN_NAME, domainName);
- domainContentValues.put(ENABLE_JAVASCRIPT, javaScriptEnabled);
- domainContentValues.put(ENABLE_FIRST_PARTY_COOKIES, firstPartyCookiesEnabled);
- domainContentValues.put(ENABLE_THIRD_PARTY_COOKIES, thirdPartyCookiesEnabled);
- domainContentValues.put(ENABLE_DOM_STORAGE, domStorageEnabled);
- domainContentValues.put(ENABLE_FORM_DATA, formDataEnabled); // Form data can be removed once the minimum API >= 26.
- domainContentValues.put(ENABLE_EASYLIST, easyListEnabled);
- domainContentValues.put(ENABLE_EASYPRIVACY, easyPrivacyEnabled);
- domainContentValues.put(ENABLE_FANBOYS_ANNOYANCE_LIST, fanboysAnnoyanceEnabled);
- domainContentValues.put(ENABLE_FANBOYS_SOCIAL_BLOCKING_LIST, fanboysSocialBlockingEnabled);
- domainContentValues.put(ENABLE_ULTRAPRIVACY, ultraPrivacyEnabled);
- domainContentValues.put(BLOCK_ALL_THIRD_PARTY_REQUESTS, blockAllThirdPartyRequests);
- domainContentValues.put(USER_AGENT, userAgent);
- domainContentValues.put(FONT_SIZE, fontSize);
- domainContentValues.put(SWIPE_TO_REFRESH, swipeToRefresh);
- domainContentValues.put(NIGHT_MODE, nightMode);
- domainContentValues.put(DISPLAY_IMAGES, displayImages);
- domainContentValues.put(PINNED_SSL_CERTIFICATE, pinnedSslCertificate);
- domainContentValues.put(SSL_ISSUED_TO_COMMON_NAME, sslIssuedToCommonName);
- domainContentValues.put(SSL_ISSUED_TO_ORGANIZATION, sslIssuedToOrganization);
- domainContentValues.put(SSL_ISSUED_TO_ORGANIZATIONAL_UNIT, sslIssuedToOrganizationalUnit);
- domainContentValues.put(SSL_ISSUED_BY_COMMON_NAME, sslIssuedByCommonName);
- domainContentValues.put(SSL_ISSUED_BY_ORGANIZATION, sslIssuedByOrganization);
- domainContentValues.put(SSL_ISSUED_BY_ORGANIZATIONAL_UNIT, sslIssuedByOrganizationalUnit);
- domainContentValues.put(SSL_START_DATE, sslStartDate);
- domainContentValues.put(SSL_END_DATE, sslEndDate);
+ // Add entries for each field in the certificate.
+ pinnedSslCertificateContentValues.put(SSL_ISSUED_TO_COMMON_NAME, sslIssuedToCommonName);
+ pinnedSslCertificateContentValues.put(SSL_ISSUED_TO_ORGANIZATION, sslIssuedToOrganization);
+ pinnedSslCertificateContentValues.put(SSL_ISSUED_TO_ORGANIZATIONAL_UNIT, sslIssuedToOrganizationalUnit);
+ pinnedSslCertificateContentValues.put(SSL_ISSUED_BY_COMMON_NAME, sslIssuedByCommonName);
+ pinnedSslCertificateContentValues.put(SSL_ISSUED_BY_ORGANIZATION, sslIssuedByOrganization);
+ pinnedSslCertificateContentValues.put(SSL_ISSUED_BY_ORGANIZATIONAL_UNIT, sslIssuedByOrganizationalUnit);
+ pinnedSslCertificateContentValues.put(SSL_START_DATE, sslStartDate);
+ pinnedSslCertificateContentValues.put(SSL_END_DATE, sslEndDate);
// Get a writable database handle.
SQLiteDatabase domainsDatabase = this.getWritableDatabase();
- // Update the row for `databaseId`. The last argument is `null` because there are no `whereArgs`.
- domainsDatabase.update(DOMAINS_TABLE, domainContentValues, _ID + " = " + databaseId, null);
+ // Update the row for database ID.
+ domainsDatabase.update(DOMAINS_TABLE, pinnedSslCertificateContentValues, _ID + " = " + databaseId, null);
// Close the database handle.
domainsDatabase.close();
}
- public void updateCertificate(int databaseId, String sslIssuedToCommonName, String sslIssuedToOrganization, String sslIssuedToOrganizationalUnit, String sslIssuedByCommonName,
- String sslIssuedByOrganization, String sslIssuedByOrganizationalUnit, long sslStartDate, long sslEndDate) {
- // Store the domain data in a `ContentValues`.
- ContentValues domainContentValues = new ContentValues();
+ public void updatePinnedIpAddresses(int databaseId, String ipAddresses) {
+ // Store the pinned IP addresses in a content values.
+ ContentValues pinnedIpAddressesContentValues = new ContentValues();
- // Add entries for each field in the certificate.
- domainContentValues.put(SSL_ISSUED_TO_COMMON_NAME, sslIssuedToCommonName);
- domainContentValues.put(SSL_ISSUED_TO_ORGANIZATION, sslIssuedToOrganization);
- domainContentValues.put(SSL_ISSUED_TO_ORGANIZATIONAL_UNIT, sslIssuedToOrganizationalUnit);
- domainContentValues.put(SSL_ISSUED_BY_COMMON_NAME, sslIssuedByCommonName);
- domainContentValues.put(SSL_ISSUED_BY_ORGANIZATION, sslIssuedByOrganization);
- domainContentValues.put(SSL_ISSUED_BY_ORGANIZATIONAL_UNIT, sslIssuedByOrganizationalUnit);
- domainContentValues.put(SSL_START_DATE, sslStartDate);
- domainContentValues.put(SSL_END_DATE, sslEndDate);
+ // Add the IP addresses to the content values.
+ pinnedIpAddressesContentValues.put(IP_ADDRESSES, ipAddresses);
// Get a writable database handle.
SQLiteDatabase domainsDatabase = this.getWritableDatabase();
- // Update the row for `databaseId`. The last argument is `null` because there are no `whereArgs`.
- domainsDatabase.update(DOMAINS_TABLE, domainContentValues, _ID + " = " + databaseId, null);
+ // Update the row for the database ID.
+ domainsDatabase.update(DOMAINS_TABLE, pinnedIpAddressesContentValues, _ID + " = " + databaseId, null);
// Close the database handle.
domainsDatabase.close();
public static final String EXPORT_SUCCESSFUL = "Export Successful";
public static final String IMPORT_SUCCESSFUL = "Import Successful";
- private static final int SCHEMA_VERSION = 3;
+ private static final int SCHEMA_VERSION = 4;
private static final String PREFERENCES_TABLE = "preferences";
// The preferences constants.
domainsContentValues.put(DomainsDatabaseHelper.SSL_ISSUED_BY_ORGANIZATIONAL_UNIT, domainsCursor.getString(domainsCursor.getColumnIndex(DomainsDatabaseHelper.SSL_ISSUED_BY_ORGANIZATIONAL_UNIT)));
domainsContentValues.put(DomainsDatabaseHelper.SSL_START_DATE, domainsCursor.getLong(domainsCursor.getColumnIndex(DomainsDatabaseHelper.SSL_START_DATE)));
domainsContentValues.put(DomainsDatabaseHelper.SSL_END_DATE, domainsCursor.getLong(domainsCursor.getColumnIndex(DomainsDatabaseHelper.SSL_END_DATE)));
+ domainsContentValues.put(DomainsDatabaseHelper.PINNED_IP_ADDRESSES, domainsCursor.getInt(domainsCursor.getColumnIndex(DomainsDatabaseHelper.PINNED_IP_ADDRESSES)));
+ domainsContentValues.put(DomainsDatabaseHelper.IP_ADDRESSES, domainsCursor.getString(domainsCursor.getColumnIndex(DomainsDatabaseHelper.IP_ADDRESSES)));
// Insert the record into the export database.
exportDatabase.insert(DomainsDatabaseHelper.DOMAINS_TABLE, null, domainsContentValues);
// Create an integer to track the number of bytes read.
int bytesRead;
- // Copy the import file to the temporary import file. Once API >= 26 `Files.copy` can be used instead.
+ // Copy the import file to the temporary import file. Once the minimum API >= 26 `Files.copy` can be used instead.
while ((bytesRead = importFileInputStream.read(transferByteArray)) > 0) {
temporaryImportFileOutputStream.write(transferByteArray, 0, bytesRead);
}
// Get a handle for the shared preference.
SharedPreferences sharedPreferences = PreferenceManager.getDefaultSharedPreferences(context);
- // Open the import database. Once API >= 27 the file can be opened directly without using the string.
+ // Open the import database. Once the minimum API >= 27 the file can be opened directly without using the string.
SQLiteDatabase importDatabase = SQLiteDatabase.openDatabase(temporaryImportFileString, null, SQLiteDatabase.OPEN_READWRITE);
// Get the database version.
// Place the font size string in the new column.
importDatabase.execSQL("UPDATE " + PREFERENCES_TABLE + " SET " + FONT_SIZE + " = " + fontSize);
+
+ case 3:
+ // Add the Pinned IP Addresses columns.
+ importDatabase.execSQL("ALTER TABLE " + DomainsDatabaseHelper.DOMAINS_TABLE + " ADD COLUMN " + DomainsDatabaseHelper.PINNED_IP_ADDRESSES + " BOOLEAN");
+ importDatabase.execSQL("ALTER TABLE " + DomainsDatabaseHelper.DOMAINS_TABLE + " ADD COLUMN " + DomainsDatabaseHelper.IP_ADDRESSES + " TEXT");
}
}
importDomainsCursor.getString(importDomainsCursor.getColumnIndex(DomainsDatabaseHelper.SSL_ISSUED_BY_ORGANIZATIONAL_UNIT)));
domainsContentValues.put(DomainsDatabaseHelper.SSL_START_DATE, importDomainsCursor.getLong(importDomainsCursor.getColumnIndex(DomainsDatabaseHelper.SSL_START_DATE)));
domainsContentValues.put(DomainsDatabaseHelper.SSL_END_DATE, importDomainsCursor.getLong(importDomainsCursor.getColumnIndex(DomainsDatabaseHelper.SSL_END_DATE)));
+ domainsContentValues.put(DomainsDatabaseHelper.PINNED_IP_ADDRESSES, importDomainsCursor.getInt(importDomainsCursor.getColumnIndex(DomainsDatabaseHelper.PINNED_IP_ADDRESSES)));
+ domainsContentValues.put(DomainsDatabaseHelper.IP_ADDRESSES, importDomainsCursor.getString(importDomainsCursor.getColumnIndex(DomainsDatabaseHelper.IP_ADDRESSES)));
// Insert the record into the export database.
domainsDatabaseHelper.addDomain(domainsContentValues);
android:descendantFocusability="beforeDescendants" >
<LinearLayout
- xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_height="wrap_content"
android:layout_width="match_parent"
android:layout_margin="12dp"
android:orientation="horizontal" >
<ImageView
- android:id="@+id/domain_settings_javascript_imageview"
+ android:id="@+id/javascript_imageview"
android:layout_height="wrap_content"
android:layout_width="wrap_content"
android:layout_marginTop="1dp"
tools:ignore="contentDescription" />
<Switch
- android:id="@+id/domain_settings_javascript_switch"
+ android:id="@+id/javascript_switch"
android:layout_height="wrap_content"
android:layout_width="match_parent"
android:layout_marginStart="8dp"
android:orientation="horizontal" >
<ImageView
- android:id="@+id/domain_settings_first_party_cookies_imageview"
+ android:id="@+id/first_party_cookies_imageview"
android:layout_height="wrap_content"
android:layout_width="wrap_content"
android:layout_marginTop="1dp"
tools:ignore="contentDescription" />
<Switch
- android:id="@+id/domain_settings_first_party_cookies_switch"
+ android:id="@+id/first_party_cookies_switch"
android:layout_height="wrap_content"
android:layout_width="match_parent"
android:layout_marginStart="8dp"
<!-- Third-Party Cookies. -->
<LinearLayout
- android:id="@+id/domain_settings_third_party_cookies_linearlayout"
+ android:id="@+id/third_party_cookies_linearlayout"
android:layout_height="wrap_content"
android:layout_width="match_parent"
android:orientation="horizontal" >
<ImageView
- android:id="@+id/domain_settings_third_party_cookies_imageview"
+ android:id="@+id/third_party_cookies_imageview"
android:layout_height="wrap_content"
android:layout_width="wrap_content"
android:layout_marginTop="1dp"
tools:ignore="contentDescription" />
<Switch
- android:id="@+id/domain_settings_third_party_cookies_switch"
+ android:id="@+id/third_party_cookies_switch"
android:layout_height="wrap_content"
android:layout_width="match_parent"
android:layout_marginStart="8dp"
android:orientation="horizontal" >
<ImageView
- android:id="@+id/domain_settings_dom_storage_imageview"
+ android:id="@+id/dom_storage_imageview"
android:layout_height="wrap_content"
android:layout_width="wrap_content"
android:layout_marginTop="1dp"
tools:ignore="contentDescription" />
<Switch
- android:id="@+id/domain_settings_dom_storage_switch"
+ android:id="@+id/dom_storage_switch"
android:layout_height="wrap_content"
android:layout_width="match_parent"
android:layout_marginStart="8dp"
android:orientation="horizontal" >
<ImageView
- android:id="@+id/domain_settings_form_data_imageview"
+ android:id="@+id/form_data_imageview"
android:layout_height="wrap_content"
android:layout_width="wrap_content"
android:layout_marginTop="1dp"
tools:ignore="contentDescription" />
<Switch
- android:id="@+id/domain_settings_form_data_switch"
+ android:id="@+id/form_data_switch"
android:layout_height="wrap_content"
android:layout_width="match_parent"
android:layout_marginStart="8dp"
android:orientation="horizontal" >
<ImageView
- android:id="@+id/domain_settings_easylist_imageview"
+ android:id="@+id/easylist_imageview"
android:layout_height="wrap_content"
android:layout_width="wrap_content"
android:layout_marginTop="1dp"
tools:ignore="contentDescription" />
<Switch
- android:id="@+id/domain_settings_easylist_switch"
+ android:id="@+id/easylist_switch"
android:layout_height="wrap_content"
android:layout_width="match_parent"
android:layout_marginStart="8dp"
android:orientation="horizontal" >
<ImageView
- android:id="@+id/domain_settings_easyprivacy_imageview"
+ android:id="@+id/easyprivacy_imageview"
android:layout_height="wrap_content"
android:layout_width="wrap_content"
android:layout_marginTop="1dp"
tools:ignore="contentDescription" />
<Switch
- android:id="@+id/domain_settings_easyprivacy_switch"
+ android:id="@+id/easyprivacy_switch"
android:layout_height="wrap_content"
android:layout_width="match_parent"
android:layout_marginStart="8dp"
android:orientation="horizontal" >
<ImageView
- android:id="@+id/domain_settings_fanboys_annoyance_list_imageview"
+ android:id="@+id/fanboys_annoyance_list_imageview"
android:layout_height="wrap_content"
android:layout_width="wrap_content"
android:layout_marginTop="1dp"
tools:ignore="contentDescription" />
<Switch
- android:id="@+id/domain_settings_fanboys_annoyance_list_switch"
+ android:id="@+id/fanboys_annoyance_list_switch"
android:layout_height="wrap_content"
android:layout_width="match_parent"
android:layout_marginStart="8dp"
android:orientation="horizontal" >
<ImageView
- android:id="@+id/domain_settings_fanboys_social_blocking_list_imageview"
+ android:id="@+id/fanboys_social_blocking_list_imageview"
android:layout_height="wrap_content"
android:layout_width="wrap_content"
android:layout_marginTop="1dp"
tools:ignore="contentDescription" />
<Switch
- android:id="@+id/domain_settings_fanboys_social_blocking_list_switch"
+ android:id="@+id/fanboys_social_blocking_list_switch"
android:layout_height="wrap_content"
android:layout_width="match_parent"
android:layout_marginStart="8dp"
android:orientation="horizontal" >
<ImageView
- android:id="@+id/domain_settings_ultraprivacy_imageview"
+ android:id="@+id/ultraprivacy_imageview"
android:layout_height="wrap_content"
android:layout_width="wrap_content"
android:layout_marginTop="1dp"
tools:ignore="contentDescription" />
<Switch
- android:id="@+id/domain_settings_ultraprivacy_switch"
+ android:id="@+id/ultraprivacy_switch"
android:layout_height="wrap_content"
android:layout_width="match_parent"
android:layout_marginStart="8dp"
android:orientation="horizontal" >
<ImageView
- android:id="@+id/domain_settings_block_all_third_party_requests_imageview"
+ android:id="@+id/block_all_third_party_requests_imageview"
android:layout_height="wrap_content"
android:layout_width="wrap_content"
android:layout_marginTop="1dp"
tools:ignore="contentDescription" />
<Switch
- android:id="@+id/domain_settings_block_all_third_party_requests_switch"
+ android:id="@+id/block_all_third_party_requests_switch"
android:layout_height="wrap_content"
android:layout_width="match_parent"
android:layout_marginStart="8dp"
android:contentDescription="@string/user_agent" />
<Spinner
- android:id="@+id/domain_settings_user_agent_spinner"
+ android:id="@+id/user_agent_spinner"
android:layout_height="wrap_content"
android:layout_width="match_parent" />
</LinearLayout>
<TextView
- android:id="@+id/domain_settings_user_agent_textview"
+ android:id="@+id/user_agent_textview"
android:layout_height="match_parent"
android:layout_width="match_parent"
android:layout_marginStart="45dp"
android:textSize="13sp" />
<EditText
- android:id="@+id/domain_settings_custom_user_agent_edittext"
+ android:id="@+id/custom_user_agent_edittext"
android:layout_height="wrap_content"
android:layout_width="match_parent"
android:layout_marginStart="40dp"
android:contentDescription="@string/font_size" />
<Spinner
- android:id="@+id/domain_settings_font_size_spinner"
+ android:id="@+id/font_size_spinner"
android:layout_height="wrap_content"
android:layout_width="match_parent" />
</LinearLayout>
<TextView
- android:id="@+id/domain_settings_font_size_textview"
+ android:id="@+id/font_size_textview"
android:layout_height="match_parent"
android:layout_width="match_parent"
android:layout_marginStart="45dp"
android:orientation="horizontal" >
<ImageView
- android:id="@+id/domain_settings_swipe_to_refresh_imageview"
+ android:id="@+id/swipe_to_refresh_imageview"
android:layout_height="wrap_content"
android:layout_width="wrap_content"
android:layout_marginTop="1dp"
android:contentDescription="@string/swipe_to_refresh" />
<Spinner
- android:id="@+id/domain_settings_swipe_to_refresh_spinner"
+ android:id="@+id/swipe_to_refresh_spinner"
android:layout_height="wrap_content"
android:layout_width="match_parent" />
</LinearLayout>
<TextView
- android:id="@+id/domain_settings_swipe_to_refresh_textview"
+ android:id="@+id/swipe_to_refresh_textview"
android:layout_height="match_parent"
android:layout_width="match_parent"
android:layout_marginStart="45dp"
android:orientation="horizontal" >
<ImageView
- android:id="@+id/domain_settings_night_mode_imageview"
+ android:id="@+id/night_mode_imageview"
android:layout_height="wrap_content"
android:layout_width="wrap_content"
android:layout_marginTop="1dp"
android:contentDescription="@string/night_mode" />
<Spinner
- android:id="@+id/domain_settings_night_mode_spinner"
+ android:id="@+id/night_mode_spinner"
android:layout_height="wrap_content"
android:layout_width="match_parent" />
</LinearLayout>
<TextView
- android:id="@+id/domain_settings_night_mode_textview"
+ android:id="@+id/night_mode_textview"
android:layout_height="match_parent"
android:layout_width="match_parent"
android:layout_marginStart="45dp"
android:orientation="horizontal" >
<ImageView
- android:id="@+id/domain_settings_display_webpage_images_imageview"
+ android:id="@+id/display_webpage_images_imageview"
android:layout_height="wrap_content"
android:layout_width="wrap_content"
android:layout_marginTop="1dp"
android:contentDescription="@string/display_webpage_images" />
<Spinner
- android:id="@+id/domain_settings_display_webpage_images_spinner"
+ android:id="@+id/display_webpage_images_spinner"
android:layout_height="wrap_content"
android:layout_width="match_parent" />
</LinearLayout>
<TextView
- android:id="@+id/domain_settings_display_webpage_images_textview"
+ android:id="@+id/display_webpage_images_textview"
android:layout_height="match_parent"
android:layout_width="match_parent"
android:layout_marginStart="45dp"
android:layout_width="match_parent"
android:orientation="vertical"
android:layout_marginTop="18dp"
- android:layout_marginBottom="32dp" >
+ android:layout_marginBottom="18dp" >
<!-- Switch -->
<LinearLayout
android:orientation="horizontal" >
<ImageView
- android:id="@+id/domain_settings_pinned_ssl_certificate_imageview"
+ android:id="@+id/pinned_ssl_certificate_imageview"
android:layout_height="wrap_content"
android:layout_width="wrap_content"
android:layout_marginTop="1dp"
tools:ignore="contentDescription" />
<Switch
- android:id="@+id/domain_settings_pinned_ssl_certificate_switch"
+ android:id="@+id/pinned_ssl_certificate_switch"
android:layout_height="wrap_content"
android:layout_width="match_parent"
android:layout_marginStart="8dp"
android:layout_height="wrap_content"
android:layout_width="match_parent"
android:layout_marginTop="10dp"
- android:layout_marginBottom="5dp"
android:layout_marginStart="10dp"
android:layout_marginEnd="10dp" >
android:id="@+id/current_website_certificate_cardview"
android:layout_height="wrap_content"
android:layout_width="match_parent"
- android:layout_marginTop="5dp"
- android:layout_marginBottom="10dp"
- android:layout_marginStart="10dp"
- android:layout_marginEnd="10dp" >
+ android:layout_margin="10dp" >
<LinearLayout
android:id="@+id/current_website_certificate_linearlayout"
android:layout_height="wrap_content"
android:layout_width="match_parent"
android:layout_marginTop="10dp"
+ android:layout_marginBottom="10dp"
android:layout_marginStart="40dp"
android:layout_marginEnd="40dp"
android:gravity="center_horizontal"
android:text="@string/load_an_encrypted_website" />
</LinearLayout>
+
+ <!-- Pinned IP Addresses -->
+ <LinearLayout
+ android:layout_height="wrap_content"
+ android:layout_width="match_parent"
+ android:orientation="vertical"
+ android:layout_marginTop="18dp"
+ android:layout_marginBottom="18dp" >
+
+ <!-- Switch -->
+ <LinearLayout
+ android:layout_height="wrap_content"
+ android:layout_width="match_parent"
+ android:orientation="horizontal" >
+
+ <ImageView
+ android:id="@+id/pinned_ip_addresses_imageview"
+ android:layout_height="wrap_content"
+ android:layout_width="wrap_content"
+ android:layout_marginTop="1dp"
+ android:layout_marginEnd="10dp"
+ android:layout_gravity="center_vertical"
+ tools:ignore="contentDescription" />
+
+ <Switch
+ android:id="@+id/pinned_ip_addresses_switch"
+ android:layout_height="wrap_content"
+ android:layout_width="match_parent"
+ android:layout_marginStart="8dp"
+ android:text="@string/pinned_ip_addresses"
+ android:textColor="?android:textColorPrimary"
+ android:textSize="18sp" />
+ </LinearLayout>
+
+ <!-- Saved IP Addresses -->
+ <android.support.v7.widget.CardView
+ android:id="@+id/saved_ip_addresses_cardview"
+ android:layout_height="wrap_content"
+ android:layout_width="match_parent"
+ android:layout_marginTop="10dp"
+ android:layout_marginStart="10dp"
+ android:layout_marginEnd="10dp" >
+
+ <LinearLayout
+ android:id="@+id/saved_ip_addresses_linearlayout"
+ android:layout_height="wrap_content"
+ android:layout_width="match_parent"
+ android:orientation="vertical"
+ android:padding="10dp" >
+
+ <RadioButton
+ android:id="@+id/saved_ip_addresses_radiobutton"
+ android:layout_height="wrap_content"
+ android:layout_width="match_parent"
+ android:text="@string/saved_ip_addresses"
+ android:textSize="17sp"
+ android:textAllCaps="true"
+ android:textStyle="bold"
+ android:textColor="?android:textColorPrimary" />
+
+ <TextView
+ android:id="@+id/saved_ip_addresses_textview"
+ android:layout_height="wrap_content"
+ android:layout_width="match_parent"
+ android:layout_marginStart="32dp"
+ android:textColor="?attr/aboutText" />
+ </LinearLayout>
+ </android.support.v7.widget.CardView>
+
+ <android.support.v7.widget.CardView
+ android:id="@+id/current_ip_addresses_cardview"
+ android:layout_height="wrap_content"
+ android:layout_width="match_parent"
+ android:layout_margin="10dp">
+
+ <LinearLayout
+ android:id="@+id/current_ip_addresses_linearlayout"
+ android:layout_height="wrap_content"
+ android:layout_width="match_parent"
+ android:orientation="vertical"
+ android:padding="10dp" >
+
+ <RadioButton
+ android:id="@+id/current_ip_addresses_radiobutton"
+ android:layout_height="wrap_content"
+ android:layout_width="match_parent"
+ android:text="@string/current_ip_addresses"
+ android:textSize="17sp"
+ android:textAllCaps="true"
+ android:textStyle="bold"
+ android:textColor="?android:textColorPrimary" />
+
+ <TextView
+ android:id="@+id/current_ip_addresses_textview"
+ android:layout_height="wrap_content"
+ android:layout_width="match_parent"
+ android:layout_marginStart="32dp"
+ android:textColor="?attr/aboutText" />
+ </LinearLayout>
+ </android.support.v7.widget.CardView>
+ </LinearLayout>
</LinearLayout>
</ScrollView>
\ No newline at end of file
--- /dev/null
+<?xml version="1.0" encoding="utf-8"?>
+
+<!--
+ Copyright © 2017-2019 Soren Stoutner <soren@stoutner.com>.
+
+ This file is part of Privacy Browser <https://www.stoutner.com/privacy-browser>.
+
+ Privacy Browser is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ Privacy Browser is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with Privacy Browser. If not, see <http://www.gnu.org/licenses/>. -->
+
+<LinearLayout
+ xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:android.support.design="http://schemas.android.com/apk/res-auto"
+ android:layout_height="wrap_content"
+ android:layout_width="wrap_content"
+ android:orientation="vertical">
+
+ <android.support.design.widget.TabLayout
+ android:id="@+id/pinned_ssl_certificate_mismatch_tablayout"
+ android:layout_height="wrap_content"
+ android:layout_width="wrap_content"
+ android.support.design:tabMode="scrollable"
+ android:theme="?attr/dialogTabLayoutTheme" />
+
+ <ScrollView
+ android:layout_height="wrap_content"
+ android:layout_width="wrap_content" >
+
+ <com.stoutner.privacybrowser.definitions.WrapVerticalContentViewPager
+ android:id="@+id/pinned_ssl_certificate_mismatch_viewpager"
+ android:layout_height="wrap_content"
+ android:layout_width="wrap_content" />
+ </ScrollView>
+</LinearLayout>
\ No newline at end of file
--- /dev/null
+<?xml version="1.0" encoding="utf-8"?>
+
+<!--
+ Copyright © 2017-2019 Soren Stoutner <soren@stoutner.com>.
+
+ This file is part of Privacy Browser <https://www.stoutner.com/privacy-browser>.
+
+ Privacy Browser is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ Privacy Browser is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with Privacy Browser. If not, see <http://www.gnu.org/licenses/>. -->
+
+<LinearLayout
+ xmlns:android="http://schemas.android.com/apk/res/android"
+ android:layout_height="wrap_content"
+ android:layout_width="wrap_content"
+ android:padding="10dp"
+ android:orientation="vertical" >
+
+ <!-- Domain. -->
+ <TextView
+ android:layout_height="wrap_content"
+ android:layout_width="wrap_content"
+ android:layout_marginTop="5dp"
+ android:text="@string/domain"
+ android:textAllCaps="true"
+ android:textStyle="bold"
+ android:textColor="?attr/sslTitle" />
+
+ <TextView
+ android:id="@+id/domain_name"
+ android:layout_height="wrap_content"
+ android:layout_width="wrap_content" />
+
+ <TextView
+ android:id="@+id/ip_addresses"
+ android:layout_height="wrap_content"
+ android:layout_width="wrap_content"/>
+
+
+ <!-- Issued To. -->
+ <TextView
+ android:layout_height="wrap_content"
+ android:layout_width="wrap_content"
+ android:layout_marginTop="15dp"
+ android:text="@string/issued_to"
+ android:textAllCaps="true"
+ android:textStyle="bold"
+ android:textColor="?attr/sslTitle" />
+
+ <TextView
+ android:id="@+id/issued_to_cname"
+ android:layout_height="wrap_content"
+ android:layout_width="wrap_content" />
+
+ <TextView
+ android:id="@+id/issued_to_oname"
+ android:layout_height="wrap_content"
+ android:layout_width="wrap_content" />
+
+ <TextView
+ android:id="@+id/issued_to_uname"
+ android:layout_height="wrap_content"
+ android:layout_width="wrap_content" />
+
+
+ <!-- Issued By. -->
+ <TextView
+ android:layout_height="wrap_content"
+ android:layout_width="wrap_content"
+ android:layout_marginTop="15dp"
+ android:text="@string/issued_by"
+ android:textAllCaps="true"
+ android:textStyle="bold"
+ android:textColor="?attr/sslTitle" />
+
+ <TextView
+ android:id="@+id/issued_by_cname"
+ android:layout_height="wrap_content"
+ android:layout_width="wrap_content" />
+
+ <TextView
+ android:id="@+id/issued_by_oname"
+ android:layout_height="wrap_content"
+ android:layout_width="wrap_content" />
+
+ <TextView
+ android:id="@+id/issued_by_uname"
+ android:layout_height="wrap_content"
+ android:layout_width="wrap_content" />
+
+
+ <!-- Valid Dates. -->
+ <TextView
+ android:layout_height="wrap_content"
+ android:layout_width="wrap_content"
+ android:layout_marginTop="15dp"
+ android:text="@string/valid_dates"
+ android:textAllCaps="true"
+ android:textStyle="bold"
+ android:textColor="?attr/sslTitle" />
+
+ <TextView
+ android:id="@+id/start_date"
+ android:layout_height="wrap_content"
+ android:layout_width="wrap_content" />
+
+ <TextView
+ android:id="@+id/end_date"
+ android:layout_height="wrap_content"
+ android:layout_width="wrap_content" />
+</LinearLayout>
\ No newline at end of file
+++ /dev/null
-<?xml version="1.0" encoding="utf-8"?>
-
-<!--
- Copyright © 2017-2018 Soren Stoutner <soren@stoutner.com>.
-
- This file is part of Privacy Browser <https://www.stoutner.com/privacy-browser>.
-
- Privacy Browser is free software: you can redistribute it and/or modify
- it under the terms of the GNU General Public License as published by
- the Free Software Foundation, either version 3 of the License, or
- (at your option) any later version.
-
- Privacy Browser is distributed in the hope that it will be useful,
- but WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- GNU General Public License for more details.
-
- You should have received a copy of the GNU General Public License
- along with Privacy Browser. If not, see <http://www.gnu.org/licenses/>. -->
-
-<LinearLayout
- xmlns:android="http://schemas.android.com/apk/res/android"
- xmlns:android.support.design="http://schemas.android.com/apk/res-auto"
- android:layout_height="wrap_content"
- android:layout_width="wrap_content"
- android:orientation="vertical">
-
- <android.support.design.widget.TabLayout
- android:id="@+id/pinned_ssl_certificate_mismatch_tablayout"
- android:layout_height="wrap_content"
- android:layout_width="wrap_content"
- android.support.design:tabMode="scrollable"
- android:theme="?attr/dialogTabLayoutTheme" />
-
- <ScrollView
- android:layout_height="wrap_content"
- android:layout_width="wrap_content" >
-
- <com.stoutner.privacybrowser.definitions.WrapVerticalContentViewPager
- android:id="@+id/pinned_ssl_certificate_mismatch_viewpager"
- android:layout_height="wrap_content"
- android:layout_width="wrap_content" />
- </ScrollView>
-</LinearLayout>
\ No newline at end of file
+++ /dev/null
-<?xml version="1.0" encoding="utf-8"?>
-
-<!--
- Copyright © 2017-2018 Soren Stoutner <soren@stoutner.com>.
-
- This file is part of Privacy Browser <https://www.stoutner.com/privacy-browser>.
-
- Privacy Browser is free software: you can redistribute it and/or modify
- it under the terms of the GNU General Public License as published by
- the Free Software Foundation, either version 3 of the License, or
- (at your option) any later version.
-
- Privacy Browser is distributed in the hope that it will be useful,
- but WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- GNU General Public License for more details.
-
- You should have received a copy of the GNU General Public License
- along with Privacy Browser. If not, see <http://www.gnu.org/licenses/>. -->
-
-<LinearLayout
- xmlns:android="http://schemas.android.com/apk/res/android"
- android:layout_height="wrap_content"
- android:layout_width="wrap_content"
- android:padding="10dp"
- android:orientation="vertical" >
-
- <!-- Issued To. -->
- <TextView
- android:layout_height="wrap_content"
- android:layout_width="wrap_content"
- android:text="@string/issued_to"
- android:textAllCaps="true"
- android:textStyle="bold"
- android:textColor="?attr/sslTitle" />
-
- <TextView
- android:id="@+id/issued_to_cname"
- android:layout_height="wrap_content"
- android:layout_width="wrap_content" />
-
- <TextView
- android:id="@+id/issued_to_oname"
- android:layout_height="wrap_content"
- android:layout_width="wrap_content" />
-
- <TextView
- android:id="@+id/issued_to_uname"
- android:layout_height="wrap_content"
- android:layout_width="wrap_content" />
-
-
- <!-- Issued By. -->
- <TextView
- android:layout_height="wrap_content"
- android:layout_width="wrap_content"
- android:layout_marginTop="15dp"
- android:text="@string/issued_by"
- android:textAllCaps="true"
- android:textStyle="bold"
- android:textColor="?attr/sslTitle" />
-
- <TextView
- android:id="@+id/issued_by_cname"
- android:layout_height="wrap_content"
- android:layout_width="wrap_content" />
-
- <TextView
- android:id="@+id/issued_by_oname"
- android:layout_height="wrap_content"
- android:layout_width="wrap_content" />
-
- <TextView
- android:id="@+id/issued_by_uname"
- android:layout_height="wrap_content"
- android:layout_width="wrap_content" />
-
-
- <!-- Valid Dates. -->
- <TextView
- android:layout_height="wrap_content"
- android:layout_width="wrap_content"
- android:layout_marginTop="15dp"
- android:text="@string/valid_dates"
- android:textAllCaps="true"
- android:textStyle="bold"
- android:textColor="?attr/sslTitle" />
-
- <TextView
- android:id="@+id/start_date"
- android:layout_height="wrap_content"
- android:layout_width="wrap_content" />
-
- <TextView
- android:id="@+id/end_date"
- android:layout_height="wrap_content"
- android:layout_width="wrap_content" />
-</LinearLayout>
\ No newline at end of file
<?xml version="1.0" encoding="utf-8"?>
<!--
- Copyright © 2016-2017 Soren Stoutner <soren@stoutner.com>.
+ Copyright © 2016-2017,2019 Soren Stoutner <soren@stoutner.com>.
This file is part of Privacy Browser <https://www.stoutner.com/privacy-browser>.
android:textColor="?attr/sslTitle" />
<TextView
- android:id="@+id/url_error_dialog"
+ android:id="@+id/url"
android:layout_height="wrap_content"
android:layout_width="wrap_content" />
+ <TextView
+ android:id="@+id/ip_addresses"
+ android:layout_height="wrap_content"
+ android:layout_width="wrap_content"
+ android:text="@string/ip_addresses" />
+
<!-- Issued To. -->
<TextView
android:layout_width="wrap_content"
android:textColor="?attr/sslTitle" />
<TextView
- android:id="@+id/issued_to_cname_error_dialog"
+ android:id="@+id/issued_to_cname"
android:layout_height="wrap_content"
android:layout_width="wrap_content" />
<TextView
- android:id="@+id/issued_to_oname_error_dialog"
+ android:id="@+id/issued_to_oname"
android:layout_height="wrap_content"
android:layout_width="wrap_content" />
<TextView
- android:id="@+id/issued_to_uname_error_dialog"
+ android:id="@+id/issued_to_uname"
android:layout_height="wrap_content"
android:layout_width="wrap_content"/>
android:textColor="?attr/sslTitle"/>
<TextView
- android:id="@+id/issued_by_cname_error_dialog"
+ android:id="@+id/issued_by_cname"
android:layout_width="wrap_content"
android:layout_height="wrap_content" />
<TextView
- android:id="@+id/issued_by_oname_error_dialog"
+ android:id="@+id/issued_by_oname"
android:layout_height="wrap_content"
android:layout_width="wrap_content" />
<TextView
- android:id="@+id/issued_by_uname_error_dialog"
+ android:id="@+id/issued_by_uname"
android:layout_height="wrap_content"
android:layout_width="wrap_content" />
android:textColor="?attr/sslTitle"/>
<TextView
- android:id="@+id/start_date_error_dialog"
+ android:id="@+id/start_date"
android:layout_height="wrap_content"
android:layout_width="wrap_content" />
<TextView
- android:id="@+id/end_date_error_dialog"
+ android:id="@+id/end_date"
android:layout_height="wrap_content"
android:layout_width="wrap_content" />
</LinearLayout>
android:checkable="true"
app:showAsAction="never" />
- <item
- android:id="@+id/print"
- android:title="@string/print"
- android:orderInCategory="970"
- app:showAsAction="never" />
-
<item
android:id="@+id/find_on_page"
android:title="@string/find_on_page"
- android:orderInCategory="980"
+ android:orderInCategory="970"
app:showAsAction="never|collapseActionView" />
- <item
- android:id="@+id/add_to_homescreen"
- android:title="@string/add_to_home_screen"
- android:orderInCategory="990"
- app:showAsAction="never" />
-
<item
android:id="@+id/view_source"
android:title="@string/view_source"
- android:orderInCategory="999"
+ android:orderInCategory="980"
app:showAsAction="never" />
</menu>
</item>
android:orderInCategory="1010"
app:showAsAction="never" />
+ <item
+ android:id="@+id/print"
+ android:title="@string/print"
+ android:orderInCategory="1020"
+ app:showAsAction="never" />
+
<item
android:id="@+id/open_with_app"
android:title="@string/open_with_app"
- android:orderInCategory="1020"
+ android:orderInCategory="1030"
app:showAsAction="never" />
<item
android:id="@+id/open_with_browser"
android:title="@string/open_with_browser"
- android:orderInCategory="1030"
+ android:orderInCategory="1040"
+ app:showAsAction="never" />
+
+ <item
+ android:id="@+id/add_to_homescreen"
+ android:title="@string/add_to_home_screen"
+ android:orderInCategory="1050"
app:showAsAction="never" />
</menu>
</item>
<string name="url">URL</string>
<string name="url_label">URL:</string>
- <!-- Pinned SSL Certificate Mismatch. -->
- <string name="update_ssl">SSL aktualisieren</string>
- <string name="ssl_certificate_mismatch">SSL-Zertifikat Mismatch</string>
- <string name="current_ssl">Aktuelles SSL</string>
- <string name="pinned_ssl">Pinned SSL</string>
+ <!-- Pinned Mismatch. -->
+ <string name="update">Aktualisieren</string>
+ <string name="current">Aktuelles</string>
<!-- HTTP Authentication. -->
<string name="http_authentication">HTTP-Authentifizierung</string>
<item>Grafiken deaktiviert</item>
</string-array>
<string name="pinned_ssl_certificate">SSL-Zertifikat verankern</string>
- <string name="saved_ssl_certificate">Gespeicherte SSL-Zertifikate</string>
- <string name="current_website_ssl_certificate">SSL-Zertifikat der aktuellen Webseite</string>
- <string name="load_an_encrypted_website">Zuerst verschlüsselte Webseite laden...</string>
+ <string name="saved_ssl_certificate">Gespeicherte SSL-Zertifikate</string>
+ <string name="current_website_ssl_certificate">SSL-Zertifikat der aktuellen Webseite</string>
+ <string name="load_an_encrypted_website">Zuerst verschlüsselte Webseite laden...</string>
<!-- Guide. -->
<string name="privacy_browser_guide">Privacy Browser Handbuch</string>
<string name="url">URL</string>
<string name="url_label">URL:</string>
- <!-- Pinned SSL Certificate Mismatch. -->
- <string name="update_ssl">Actualizar SSL</string>
- <string name="ssl_certificate_mismatch">No coinciden los certificados SSL</string>
- <string name="current_ssl">SSL actual</string>
- <string name="pinned_ssl">SSL fijado</string>
+ <!-- Pinned Mismatch. -->
+ <string name="update">Actualizar</string>
+ <string name="current">Actual</string>
+ <string name="pinned">Fijado</string>
<!-- HTTP Authentication. -->
<string name="http_authentication">Autenticación HTTP</string>
<item>Imágenes deshabilitadas</item>
</string-array>
<string name="pinned_ssl_certificate">Certificado SSL fijado</string>
- <string name="saved_ssl_certificate">Certificado SSL guardado</string>
- <string name="current_website_ssl_certificate">Certificado SSL actual de la web</string>
- <string name="load_an_encrypted_website">Cargar una página web cifrada antes de abrir la configuración de dominio para rellenar el certificado SSL de la página web actual.</string>
+ <string name="saved_ssl_certificate">Certificado SSL guardado</string>
+ <string name="current_website_ssl_certificate">Certificado SSL actual de la web</string>
+ <string name="load_an_encrypted_website">Cargar una página web cifrada antes de abrir la configuración de dominio para rellenar el certificado SSL de la página web actual.</string>
<!-- Import/Export. -->
<string name="encryption">Cifrado</string>
<string name="url">URL</string>
<string name="url_label">URL:</string>
- <!-- Pinned SSL Certificate Mismatch. -->
- <string name="update_ssl">Aggiorna SSL</string>
- <string name="ssl_certificate_mismatch">Incompatibilità certificato SSL</string>
- <string name="current_ssl">SSL attuale</string>
- <string name="pinned_ssl">SSL appuntato</string>
+ <!-- Pinned Mismatch. -->
+ <string name="update">Aggiorna</string>
+ <string name="current">Attuale</string>
+ <string name="pinned">Appuntato</string>
<!-- HTTP Authentication. -->
<string name="http_authentication">Autenticazione HTTP</string>
<item>Immagini disabilitate</item>
</string-array>
<string name="pinned_ssl_certificate">Certificato SSL appuntato</string>
- <string name="saved_ssl_certificate">Certificato SSL salvato</string>
- <string name="current_website_ssl_certificate">Certificato SSL di questo sito</string>
- <string name="load_an_encrypted_website">Carica un sito Web criptato prima di aprire le impostazioni dei domini per popolare il certificato SSL del sito attuale.</string>
+ <string name="saved_ssl_certificate">Certificato SSL salvato</string>
+ <string name="current_website_ssl_certificate">Certificato SSL di questo sito</string>
+ <string name="load_an_encrypted_website">Carica un sito Web criptato prima di aprire le impostazioni dei domini per popolare il certificato SSL del sito attuale.</string>
<!-- Import/Export. -->
<string name="encryption">Cifratura</string>
<string name="url_label">URL:</string>
<!-- Pinned SSL Certificate Mismatch. -->
- <string name="update_ssl">Обновление SSL</string>
- <string name="ssl_certificate_mismatch">Несоответствие сертификата SSL</string>
- <string name="current_ssl">Текущий SSL</string>
- <string name="pinned_ssl">Закрепленный SSL</string>
+ <string name="update">Обновление</string>
+ <string name="current">Текущий</string>
+ <string name="pinned">Закрепленный</string>
<!-- HTTP Authentication. -->
<string name="http_authentication">Аутентификация HTTP</string>
<item>Изображения выключены</item>
</string-array>
<string name="pinned_ssl_certificate">Закрепленный сертификат SSL</string>
- <string name="saved_ssl_certificate">Сохраненный сертификат SSL</string>
- <string name="current_website_ssl_certificate">Текущий сертификат SSL сайта</string>
- <string name="load_an_encrypted_website">Откройте зашифрованный сайт перед настройкой домена, чтобы заполнить текущий сертификат SSL веб-сайта.</string>
+ <string name="saved_ssl_certificate">Сохраненный сертификат SSL</string>
+ <string name="current_website_ssl_certificate">Текущий сертификат SSL сайта</string>
+ <string name="load_an_encrypted_website">Откройте зашифрованный сайт перед настройкой домена, чтобы заполнить текущий сертификат SSL веб-сайта.</string>
<!-- Import/Export. -->
<string name="encryption">Шифрование</string>
<string name="url">URL</string>
<string name="url_label">URL:</string>
- <!-- Pinned SSL Certificate Mismatch. -->
- <string name="update_ssl">SSL güncelle</string>
- <string name="ssl_certificate_mismatch">SSL Sertifikası Uyumsuzluğu</string>
- <string name="current_ssl">Geçerli SSL</string>
- <string name="pinned_ssl">İğneli SSL</string>
+ <!-- Pinned Mismatch. -->
+ <string name="update">Güncelle</string>
+ <string name="current">Geçerli</string>
+ <string name="pinned">İğneli</string>
<!-- HTTP Authentication. -->
<string name="http_authentication">HTTP Kimlik Doğrulama</string>
<item>Resimler devre dışı</item>
</string-array>
<string name="pinned_ssl_certificate">İğneli SSL sertifikası</string>
- <string name="saved_ssl_certificate">Kayıtlı SSL sertifikası</string>
- <string name="current_website_ssl_certificate">Geçerli web sitesi SSL sertifikası</string>
- <string name="load_an_encrypted_website">Geçerli web sitesinin SSL sertifikasını doldurmak için Domain Ayarlarını açmadan önce şifrelenmiş bir web sitesi yükleyin.</string>
+ <string name="saved_ssl_certificate">Kayıtlı SSL sertifikası</string>
+ <string name="current_website_ssl_certificate">Geçerli web sitesi SSL sertifikası</string>
+ <string name="load_an_encrypted_website">Geçerli web sitesinin SSL sertifikasını doldurmak için Domain Ayarlarını açmadan önce şifrelenmiş bir web sitesi yükleyin.</string>
<!-- Import/Export. -->
<string name="encryption">Şifreleme</string>
<string name="url">URL</string>
<string name="url_label">URL:</string>
- <!-- Pinned SSL Certificate Mismatch. -->
- <string name="update_ssl">Update SSL</string>
- <string name="ssl_certificate_mismatch">SSL Certificate Mismatch</string>
- <string name="current_ssl">Current SSL</string>
- <string name="pinned_ssl">Pinned SSL</string>
+ <!-- Pinned Mismatch. -->
+ <string name="pinned_mismatch">Pinned Mismatch</string>
+ <string name="update">Update</string>
+ <string name="current">Current</string>
+ <string name="pinned">Pinned</string>
<!-- HTTP Authentication. -->
<string name="http_authentication">HTTP Authentication</string>
<item>Images disabled</item>
</string-array>
<string name="pinned_ssl_certificate">Pinned SSL certificate</string>
- <string name="saved_ssl_certificate">Saved SSL certificate</string>
- <string name="current_website_ssl_certificate">Current website SSL certificate</string>
- <string name="load_an_encrypted_website">Load an encrypted website before opening Domain Settings to populate the current website SSL certificate.</string>
+ <string name="saved_ssl_certificate">Saved SSL certificate</string>
+ <string name="current_website_ssl_certificate">Current website SSL certificate</string>
+ <string name="load_an_encrypted_website">Load an encrypted website before opening Domain Settings to populate the current website SSL certificate.</string>
+ <string name="pinned_ip_addresses">Pinned IP addresses</string>
+ <string name="saved_ip_addresses">Saved IP addresses</string>
+ <string name="current_ip_addresses">Current IP addresses</string>
<!-- Import/Export. -->
<string name="encryption">Encryption</string>