]> gitweb.stoutner.com Git - PrivacyBrowserAndroid.git/blob - app/src/main/java/com/stoutner/privacybrowser/adapters/PinnedMismatchPagerAdapter.kt
8953d8545b53d493e5be160c49139c761530964f
[PrivacyBrowserAndroid.git] / app / src / main / java / com / stoutner / privacybrowser / adapters / PinnedMismatchPagerAdapter.kt
1 /*
2  * Copyright © 2021-2022 Soren Stoutner <soren@stoutner.com>.
3  *
4  * This file is part of Privacy Browser Android <https://www.stoutner.com/privacy-browser-android>.
5  *
6  * Privacy Browser Android is free software: you can redistribute it and/or modify
7  * it under the terms of the GNU General Public License as published by
8  * the Free Software Foundation, either version 3 of the License, or
9  * (at your option) any later version.
10  *
11  * Privacy Browser Android is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14  * GNU General Public License for more details.
15  *
16  * You should have received a copy of the GNU General Public License
17  * along with Privacy Browser Android.  If not, see <http://www.gnu.org/licenses/>.
18  */
19
20 package com.stoutner.privacybrowser.adapters
21
22 import android.content.Context
23 import android.net.Uri
24 import android.text.SpannableStringBuilder
25 import android.text.Spanned
26 import android.text.style.ForegroundColorSpan
27 import android.view.LayoutInflater
28 import android.view.View
29 import android.view.ViewGroup
30 import android.widget.TextView
31
32 import androidx.viewpager.widget.PagerAdapter
33
34 import com.stoutner.privacybrowser.R
35 import com.stoutner.privacybrowser.activities.MainWebViewActivity
36 import com.stoutner.privacybrowser.views.NestedScrollWebView
37
38 import java.text.DateFormat
39 import java.util.Date
40
41 // This adapter uses a PagerAdapter instead of a FragmentPagerAdapter because dialogs fragments really don't like having a nested FragmentPagerAdapter inside of them.
42 class PinnedMismatchPagerAdapter(private val context: Context, private val layoutInflater: LayoutInflater, private val webViewFragmentId: Long) : PagerAdapter() {
43     override fun isViewFromObject(view: View, `object`: Any): Boolean {
44         // Check to see if the view and the object are the same.
45         return view === `object`
46     }
47
48     // Get the number of tabs.
49     override fun getCount(): Int {
50         // There are two tabs.
51         return 2
52     }
53
54     // Get the name of each tab.  Tab numbers start at 0.
55     override fun getPageTitle(tabNumber: Int): CharSequence {
56         return when (tabNumber) {
57             0 -> context.getString(R.string.current)
58             1 -> context.getString(R.string.pinned)
59             else -> ""
60         }
61     }
62
63     // Setup each tab.
64     override fun instantiateItem(container: ViewGroup, tabNumber: Int): Any {
65         // Get the current position of this WebView fragment.
66         val webViewPosition = MainWebViewActivity.webViewPagerAdapter.getPositionForId(webViewFragmentId)
67
68         // Get the WebView tab fragment.
69         val webViewTabFragment = MainWebViewActivity.webViewPagerAdapter.getPageFragment(webViewPosition)
70
71         // Get the WebView fragment view.
72         val webViewFragmentView = webViewTabFragment.requireView()
73
74         // Get a handle for the current WebView.
75         val nestedScrollWebView = webViewFragmentView.findViewById<NestedScrollWebView>(R.id.nestedscroll_webview)!!
76
77         // Inflate the scroll view for this tab.
78         val tabLayout = layoutInflater.inflate(R.layout.pinned_mismatch_tab_linearlayout, container, false) as ViewGroup
79
80         // Get handles for the views.
81         val domainNameTextView = tabLayout.findViewById<TextView>(R.id.domain_name)
82         val ipAddressesTextView = tabLayout.findViewById<TextView>(R.id.ip_addresses)
83         val issuedToCNameTextView = tabLayout.findViewById<TextView>(R.id.issued_to_cname)
84         val issuedToONameTextView = tabLayout.findViewById<TextView>(R.id.issued_to_oname)
85         val issuedToUNameTextView = tabLayout.findViewById<TextView>(R.id.issued_to_uname)
86         val issuedByCNameTextView = tabLayout.findViewById<TextView>(R.id.issued_by_cname)
87         val issuedByONameTextView = tabLayout.findViewById<TextView>(R.id.issued_by_oname)
88         val issuedByUNameTextView = tabLayout.findViewById<TextView>(R.id.issued_by_uname)
89         val startDateTextView = tabLayout.findViewById<TextView>(R.id.start_date)
90         val endDateTextView = tabLayout.findViewById<TextView>(R.id.end_date)
91
92         // Setup the labels.
93         val domainNameLabel = context.getString(R.string.domain_label) + "  "
94         val ipAddressesLabel = context.getString(R.string.ip_addresses) + "  "
95         val cNameLabel = context.getString(R.string.common_name) + "  "
96         val oNameLabel = context.getString(R.string.organization) + "  "
97         val uNameLabel = context.getString(R.string.organizational_unit) + "  "
98         val startDateLabel = context.getString(R.string.start_date) + "  "
99         val endDateLabel = context.getString(R.string.end_date) + "  "
100
101         // Convert the URL to a URI.
102         val currentUri = Uri.parse(nestedScrollWebView.url)
103
104         // Get the current host from the URI.
105         val domainName = currentUri.host
106
107         // Get the current website SSL certificate.
108         val sslCertificate = nestedScrollWebView.certificate
109
110         // Initialize the SSL certificate variables.
111         var currentSslIssuedToCName = ""
112         var currentSslIssuedToOName = ""
113         var currentSslIssuedToUName = ""
114         var currentSslIssuedByCName = ""
115         var currentSslIssuedByOName = ""
116         var currentSslIssuedByUName = ""
117         var currentSslStartDate: Date? = null
118         var currentSslEndDate: Date? = null
119
120         // Extract the individual pieces of information from the current website SSL certificate if it is not null.
121         if (sslCertificate != null) {
122             currentSslIssuedToCName = sslCertificate.issuedTo.cName
123             currentSslIssuedToOName = sslCertificate.issuedTo.oName
124             currentSslIssuedToUName = sslCertificate.issuedTo.uName
125             currentSslIssuedByCName = sslCertificate.issuedBy.cName
126             currentSslIssuedByOName = sslCertificate.issuedBy.oName
127             currentSslIssuedByUName = sslCertificate.issuedBy.uName
128             currentSslStartDate = sslCertificate.validNotBeforeDate
129             currentSslEndDate = sslCertificate.validNotAfterDate
130         }
131
132         // Get the pinned SSL certificate pair.
133         val pinnedSslCertificatePair = nestedScrollWebView.getPinnedSslCertificate()
134
135         // Extract the arrays from the array list.
136         val pinnedSslCertificateStringArray = pinnedSslCertificatePair.first
137         val pinnedSslCertificateDateArray = pinnedSslCertificatePair.second
138
139         // Setup the domain name spannable string builder.
140         val domainNameStringBuilder = SpannableStringBuilder(domainNameLabel + domainName)
141
142         // Initialize the spannable string builders.
143         val ipAddressesStringBuilder: SpannableStringBuilder
144         val issuedToCNameStringBuilder: SpannableStringBuilder
145         val issuedToONameStringBuilder: SpannableStringBuilder
146         val issuedToUNameStringBuilder: SpannableStringBuilder
147         val issuedByCNameStringBuilder: SpannableStringBuilder
148         val issuedByONameStringBuilder: SpannableStringBuilder
149         val issuedByUNameStringBuilder: SpannableStringBuilder
150         val startDateStringBuilder: SpannableStringBuilder
151         val endDateStringBuilder: SpannableStringBuilder
152
153         // Setup the spannable string builders for each tab.
154         if (tabNumber == 0) {  // Setup the current settings tab.
155             // Create the string builders.
156             ipAddressesStringBuilder = SpannableStringBuilder(ipAddressesLabel + nestedScrollWebView.currentIpAddresses)
157             issuedToCNameStringBuilder = SpannableStringBuilder(cNameLabel + currentSslIssuedToCName)
158             issuedToONameStringBuilder = SpannableStringBuilder(oNameLabel + currentSslIssuedToOName)
159             issuedToUNameStringBuilder = SpannableStringBuilder(uNameLabel + currentSslIssuedToUName)
160             issuedByCNameStringBuilder = SpannableStringBuilder(cNameLabel + currentSslIssuedByCName)
161             issuedByONameStringBuilder = SpannableStringBuilder(oNameLabel + currentSslIssuedByOName)
162             issuedByUNameStringBuilder = SpannableStringBuilder(uNameLabel + currentSslIssuedByUName)
163
164             // Set the dates if they aren't null.  Formatting a null date causes a crash.
165             startDateStringBuilder = if (currentSslStartDate == null) {
166                 SpannableStringBuilder(startDateLabel)
167             } else {
168                 SpannableStringBuilder(startDateLabel + DateFormat.getDateTimeInstance(DateFormat.MEDIUM, DateFormat.LONG).format(currentSslStartDate))
169             }
170
171             endDateStringBuilder = if (currentSslEndDate == null) {
172                 SpannableStringBuilder(endDateLabel)
173             } else {
174                 SpannableStringBuilder(endDateLabel + DateFormat.getDateTimeInstance(DateFormat.MEDIUM, DateFormat.LONG).format(currentSslEndDate))
175             }
176         } else {  // Setup the pinned settings tab.
177             // Create the string builders.
178             ipAddressesStringBuilder = SpannableStringBuilder(ipAddressesLabel + nestedScrollWebView.pinnedIpAddresses)
179             issuedToCNameStringBuilder = SpannableStringBuilder(cNameLabel + pinnedSslCertificateStringArray[0])
180             issuedToONameStringBuilder = SpannableStringBuilder(oNameLabel + pinnedSslCertificateStringArray[1])
181             issuedToUNameStringBuilder = SpannableStringBuilder(uNameLabel + pinnedSslCertificateStringArray[2])
182             issuedByCNameStringBuilder = SpannableStringBuilder(cNameLabel + pinnedSslCertificateStringArray[3])
183             issuedByONameStringBuilder = SpannableStringBuilder(oNameLabel + pinnedSslCertificateStringArray[4])
184             issuedByUNameStringBuilder = SpannableStringBuilder(uNameLabel + pinnedSslCertificateStringArray[5])
185             startDateStringBuilder = SpannableStringBuilder(startDateLabel + DateFormat.getDateTimeInstance(DateFormat.MEDIUM, DateFormat.LONG).format(pinnedSslCertificateDateArray[0]))
186             endDateStringBuilder = SpannableStringBuilder(endDateLabel + DateFormat.getDateTimeInstance(DateFormat.MEDIUM, DateFormat.LONG).format(pinnedSslCertificateDateArray[1]))
187         }
188
189         // Create the color spans.
190         val blueColorSpan = ForegroundColorSpan(context.getColor(R.color.blue_text))
191         val redColorSpan = ForegroundColorSpan(context.getColor(R.color.red_text))
192
193         // Set the domain name to be blue.
194         domainNameStringBuilder.setSpan(blueColorSpan, domainNameLabel.length, domainNameStringBuilder.length, Spanned.SPAN_INCLUSIVE_INCLUSIVE)
195
196         // Color coordinate the IP addresses if they are pinned.
197         if (nestedScrollWebView.pinnedIpAddresses != "") {
198             if (nestedScrollWebView.currentIpAddresses == nestedScrollWebView.pinnedIpAddresses) {
199                 ipAddressesStringBuilder.setSpan(blueColorSpan, ipAddressesLabel.length, ipAddressesStringBuilder.length, Spanned.SPAN_INCLUSIVE_INCLUSIVE)
200             } else {
201                 ipAddressesStringBuilder.setSpan(redColorSpan, ipAddressesLabel.length, ipAddressesStringBuilder.length, Spanned.SPAN_INCLUSIVE_INCLUSIVE)
202             }
203         }
204
205         // Color coordinate the SSL certificate fields if they are pinned.
206         if (nestedScrollWebView.hasPinnedSslCertificate()) {
207             if (currentSslIssuedToCName == pinnedSslCertificateStringArray[0]) {
208                 issuedToCNameStringBuilder.setSpan(blueColorSpan, cNameLabel.length, issuedToCNameStringBuilder.length, Spanned.SPAN_INCLUSIVE_INCLUSIVE)
209             } else {
210                 issuedToCNameStringBuilder.setSpan(redColorSpan, cNameLabel.length, issuedToCNameStringBuilder.length, Spanned.SPAN_INCLUSIVE_INCLUSIVE)
211             }
212
213             if (currentSslIssuedToOName == pinnedSslCertificateStringArray[1]) {
214                 issuedToONameStringBuilder.setSpan(blueColorSpan, oNameLabel.length, issuedToONameStringBuilder.length, Spanned.SPAN_INCLUSIVE_INCLUSIVE)
215             } else {
216                 issuedToONameStringBuilder.setSpan(redColorSpan, oNameLabel.length, issuedToONameStringBuilder.length, Spanned.SPAN_INCLUSIVE_INCLUSIVE)
217             }
218
219             if (currentSslIssuedToUName == pinnedSslCertificateStringArray[2]) {
220                 issuedToUNameStringBuilder.setSpan(blueColorSpan, uNameLabel.length, issuedToUNameStringBuilder.length, Spanned.SPAN_INCLUSIVE_INCLUSIVE)
221             } else {
222                 issuedToUNameStringBuilder.setSpan(redColorSpan, uNameLabel.length, issuedToUNameStringBuilder.length, Spanned.SPAN_INCLUSIVE_INCLUSIVE)
223             }
224
225             if (currentSslIssuedByCName == pinnedSslCertificateStringArray[3]) {
226                 issuedByCNameStringBuilder.setSpan(blueColorSpan, cNameLabel.length, issuedByCNameStringBuilder.length, Spanned.SPAN_INCLUSIVE_INCLUSIVE)
227             } else {
228                 issuedByCNameStringBuilder.setSpan(redColorSpan, cNameLabel.length, issuedByCNameStringBuilder.length, Spanned.SPAN_INCLUSIVE_INCLUSIVE)
229             }
230
231             if (currentSslIssuedByOName == pinnedSslCertificateStringArray[4]) {
232                 issuedByONameStringBuilder.setSpan(blueColorSpan, oNameLabel.length, issuedByONameStringBuilder.length, Spanned.SPAN_INCLUSIVE_INCLUSIVE)
233             } else {
234                 issuedByONameStringBuilder.setSpan(redColorSpan, oNameLabel.length, issuedByONameStringBuilder.length, Spanned.SPAN_INCLUSIVE_INCLUSIVE)
235             }
236
237             if (currentSslIssuedByUName == pinnedSslCertificateStringArray[5]) {
238                 issuedByUNameStringBuilder.setSpan(blueColorSpan, uNameLabel.length, issuedByUNameStringBuilder.length, Spanned.SPAN_INCLUSIVE_INCLUSIVE)
239             } else {
240                 issuedByUNameStringBuilder.setSpan(redColorSpan, uNameLabel.length, issuedByUNameStringBuilder.length, Spanned.SPAN_INCLUSIVE_INCLUSIVE)
241             }
242
243             if (currentSslStartDate != null && currentSslStartDate == pinnedSslCertificateDateArray[0]) {
244                 startDateStringBuilder.setSpan(blueColorSpan, startDateLabel.length, startDateStringBuilder.length, Spanned.SPAN_INCLUSIVE_INCLUSIVE)
245             } else {
246                 startDateStringBuilder.setSpan(redColorSpan, startDateLabel.length, startDateStringBuilder.length, Spanned.SPAN_INCLUSIVE_INCLUSIVE)
247             }
248
249             if (currentSslEndDate != null && currentSslEndDate == pinnedSslCertificateDateArray[1]) {
250                 endDateStringBuilder.setSpan(blueColorSpan, endDateLabel.length, endDateStringBuilder.length, Spanned.SPAN_INCLUSIVE_INCLUSIVE)
251             } else {
252                 endDateStringBuilder.setSpan(redColorSpan, endDateLabel.length, endDateStringBuilder.length, Spanned.SPAN_INCLUSIVE_INCLUSIVE)
253             }
254         }
255
256         // Display the strings.
257         domainNameTextView.text = domainNameStringBuilder
258         ipAddressesTextView.text = ipAddressesStringBuilder
259         issuedToCNameTextView.text = issuedToCNameStringBuilder
260         issuedToONameTextView.text = issuedToONameStringBuilder
261         issuedToUNameTextView.text = issuedToUNameStringBuilder
262         issuedByCNameTextView.text = issuedByCNameStringBuilder
263         issuedByONameTextView.text = issuedByONameStringBuilder
264         issuedByUNameTextView.text = issuedByUNameStringBuilder
265         startDateTextView.text = startDateStringBuilder
266         endDateTextView.text = endDateStringBuilder
267
268         // Add the tab layout to the container.  This needs to be manually done for pager adapters.
269         container.addView(tabLayout)
270
271         // Return the tab layout.
272         return tabLayout
273     }
274 }