X-Git-Url: https://gitweb.stoutner.com/?p=PrivacyBrowserAndroid.git;a=blobdiff_plain;f=app%2Fsrc%2Fmain%2Fjava%2Fcom%2Fstoutner%2Fprivacybrowser%2Fdialogs%2FViewSslCertificateDialog.java;h=c236d3a86e78061a3a581ab2e012fd269de48afd;hp=90a13271993f2cd24759d7a38c9535c69b833309;hb=892e8297ba8d23a37c091fb38325929dcf7d17c9;hpb=9c9159715c89e30aec11ae7e7a1d7591006e5cbe diff --git a/app/src/main/java/com/stoutner/privacybrowser/dialogs/ViewSslCertificateDialog.java b/app/src/main/java/com/stoutner/privacybrowser/dialogs/ViewSslCertificateDialog.java index 90a13271..c236d3a8 100644 --- a/app/src/main/java/com/stoutner/privacybrowser/dialogs/ViewSslCertificateDialog.java +++ b/app/src/main/java/com/stoutner/privacybrowser/dialogs/ViewSslCertificateDialog.java @@ -1,5 +1,5 @@ /* - * Copyright © 2016-2018 Soren Stoutner . + * Copyright © 2016-2019 Soren Stoutner . * * This file is part of Privacy Browser . * @@ -20,6 +20,7 @@ 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; @@ -27,6 +28,7 @@ import android.graphics.drawable.BitmapDrawable; 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; @@ -38,6 +40,9 @@ import android.widget.TextView; 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; @@ -113,8 +118,9 @@ public class ViewSslCertificateDialog extends DialogFragment { // The alert dialog must be shown before items in the layout can be modified. alertDialog.show(); - // Get handles for the `TextViews`. + // Get handles for the text views. TextView domainTextView = alertDialog.findViewById(R.id.domain); + TextView ipAddressesTextView = alertDialog.findViewById(R.id.ip_addresses); 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); @@ -132,43 +138,46 @@ public class ViewSslCertificateDialog extends DialogFragment { String startDateLabel = getString(R.string.start_date) + " "; String endDateLabel = getString(R.string.end_date) + " "; - // Parse `formattedUrlString` to a `URI`. + // Convert the formatted URL string to a URI. Uri uri = Uri.parse(MainWebViewActivity.formattedUrlString); - // Extract the domain name from `uri`. + // 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; // Get the strings from the SSL certificate. - String issuedToCNameString = sslCertificate.getIssuedTo().getCName(); - String issuedToONameString = sslCertificate.getIssuedTo().getOName(); - String issuedToUNameString = sslCertificate.getIssuedTo().getUName(); - String issuedByCNameString = sslCertificate.getIssuedBy().getCName(); - String issuedByONameString = sslCertificate.getIssuedBy().getOName(); - String issuedByUNameString = sslCertificate.getIssuedBy().getUName(); + String issuedToCName = sslCertificate.getIssuedTo().getCName(); + String issuedToOName = sslCertificate.getIssuedTo().getOName(); + String issuedToUName = sslCertificate.getIssuedTo().getUName(); + String issuedByCName = sslCertificate.getIssuedBy().getCName(); + String issuedByOName = sslCertificate.getIssuedBy().getOName(); + String issuedByUName = sslCertificate.getIssuedBy().getUName(); Date startDate = sslCertificate.getValidNotBeforeDate(); Date endDate = sslCertificate.getValidNotAfterDate(); - // Create a `SpannableStringBuilder` for each `TextView` that needs multiple colors of text. + // Create spannable string builders for each text view that needs multiple colors of text. SpannableStringBuilder domainStringBuilder = new SpannableStringBuilder(domainLabel + domainString); - SpannableStringBuilder issuedToCNameStringBuilder = new SpannableStringBuilder(cNameLabel + issuedToCNameString); - SpannableStringBuilder issuedToONameStringBuilder = new SpannableStringBuilder(oNameLabel + issuedToONameString); - SpannableStringBuilder issuedToUNameStringBuilder = new SpannableStringBuilder(uNameLabel + issuedToUNameString); - SpannableStringBuilder issuedByCNameStringBuilder = new SpannableStringBuilder(cNameLabel + issuedByCNameString); - SpannableStringBuilder issuedByONameStringBuilder = new SpannableStringBuilder(oNameLabel + issuedByONameString); - SpannableStringBuilder issuedByUNameStringBuilder = new SpannableStringBuilder(uNameLabel + issuedByUNameString); + SpannableStringBuilder issuedToCNameStringBuilder = new SpannableStringBuilder(cNameLabel + issuedToCName); + SpannableStringBuilder issuedToONameStringBuilder = new SpannableStringBuilder(oNameLabel + issuedToOName); + SpannableStringBuilder issuedToUNameStringBuilder = new SpannableStringBuilder(uNameLabel + issuedToUName); + SpannableStringBuilder issuedByCNameStringBuilder = new SpannableStringBuilder(cNameLabel + issuedByCName); + SpannableStringBuilder issuedByONameStringBuilder = new SpannableStringBuilder(oNameLabel + issuedByOName); + SpannableStringBuilder issuedByUNameStringBuilder = new SpannableStringBuilder(uNameLabel + issuedByUName); SpannableStringBuilder startDateStringBuilder = new SpannableStringBuilder(startDateLabel + DateFormat.getDateTimeInstance(DateFormat.MEDIUM, DateFormat.LONG).format(startDate)); SpannableStringBuilder endDateStringBuilder = new SpannableStringBuilder(endDateLabel + DateFormat.getDateTimeInstance(DateFormat.MEDIUM, DateFormat.LONG).format(endDate)); - // Create a red `ForegroundColorSpan`. We have to use the deprecated `getColor` until API >= 23. + // Create a red foreground color span. The deprecated `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`. + // Create a blue foreground color span. 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 `getColor()` must be used until the minimum API >= 23. if (MainWebViewActivity.darkTheme) { //noinspection deprecation blueColorSpan = new ForegroundColorSpan(getResources().getColor(R.color.blue_400)); @@ -177,14 +186,17 @@ public class ViewSslCertificateDialog extends DialogFragment { blueColorSpan = new ForegroundColorSpan(getResources().getColor(R.color.blue_700)); } + // Remove the incorrect lint error that `.equals` might produce a NullPointerException. + assert domainString != null; + // Formet the `domainString` and `issuedToCName` colors. - if (domainString.equals(issuedToCNameString)) { // `domainString` and `issuedToCNameString` match. + 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(blueColorSpan, cNameLabel.length(), issuedToCNameStringBuilder.length(), Spanned.SPAN_INCLUSIVE_INCLUSIVE); - } else if(issuedToCNameString.startsWith("*.")){ // `issuedToCNameString` begins with a wildcard. + } else if(issuedToCName.startsWith("*.")){ // `issuedToCName` begins with a wildcard. // Remove the initial `*.`. - String baseCertificateDomain = issuedToCNameString.substring(2); + String baseCertificateDomain = issuedToCName.substring(2); // Setup a copy of `domainString` to test subdomains. String domainStringSubdomain = domainString; @@ -219,7 +231,7 @@ public class ViewSslCertificateDialog extends DialogFragment { issuedToCNameStringBuilder.setSpan(redColorSpan, cNameLabel.length(), issuedToCNameStringBuilder.length(), Spanned.SPAN_INCLUSIVE_INCLUSIVE); } - // Setup 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 issued to and issued by spans to display the certificate information in blue. `SPAN_INCLUSIVE_INCLUSIVE` allows the span to grow in either direction. 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); @@ -244,6 +256,7 @@ public class ViewSslCertificateDialog extends DialogFragment { // Display the strings. domainTextView.setText(domainStringBuilder); + ipAddressesTextView.setText(getString(R.string.ip_addresses)); issuedToCNameTextView.setText(issuedToCNameStringBuilder); issuedToONameTextView.setText(issuedToONameStringBuilder); issuedToUNameTextView.setText(issuedToUNameStringBuilder); @@ -257,4 +270,97 @@ public class ViewSslCertificateDialog extends DialogFragment { 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 { + // The weak references are used to determine if the activity or the alert dialog have disappeared while the AsyncTask is running. + private WeakReference activityWeakReference; + private WeakReference 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