2 * Copyright © 2018-2019,2021-2022 Soren Stoutner <soren@stoutner.com>.
4 * This file is part of Privacy Browser Android <https://www.stoutner.com/privacy-browser-android>.
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.
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.
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/>.
20 package com.stoutner.privacybrowser.helpers
22 import android.app.Activity
24 import androidx.fragment.app.DialogFragment
25 import androidx.fragment.app.FragmentManager
27 import com.stoutner.privacybrowser.R
28 import com.stoutner.privacybrowser.activities.MainWebViewActivity
29 import com.stoutner.privacybrowser.dataclasses.PendingDialog
30 import com.stoutner.privacybrowser.dialogs.PinnedMismatchDialog.Companion.displayDialog
31 import com.stoutner.privacybrowser.views.NestedScrollWebView
33 import java.lang.Exception
37 object CheckPinnedMismatchHelper {
39 fun checkPinnedMismatch(activity: Activity, fragmentManager: FragmentManager, nestedScrollWebView: NestedScrollWebView) {
40 // Initialize the current SSL certificate variables.
41 var currentWebsiteIssuedToCName = ""
42 var currentWebsiteIssuedToOName = ""
43 var currentWebsiteIssuedToUName = ""
44 var currentWebsiteIssuedByCName = ""
45 var currentWebsiteIssuedByOName = ""
46 var currentWebsiteIssuedByUName = ""
47 var currentWebsiteSslStartDate: Date? = null
48 var currentWebsiteSslEndDate: Date? = null
50 // Initialize the pinned SSL certificate variables.
51 var pinnedSslIssuedToCName = ""
52 var pinnedSslIssuedToOName = ""
53 var pinnedSslIssuedToUName = ""
54 var pinnedSslIssuedByCName = ""
55 var pinnedSslIssuedByOName = ""
56 var pinnedSslIssuedByUName = ""
57 var pinnedSslStartDate: Date? = null
58 var pinnedSslEndDate: Date? = null
60 // Get the current website SSL certificate.
61 val currentWebsiteSslCertificate = nestedScrollWebView.certificate
63 // Extract the individual pieces of information from the current website SSL certificate if it is not null.
64 if (currentWebsiteSslCertificate != null) {
65 currentWebsiteIssuedToCName = currentWebsiteSslCertificate.issuedTo.cName
66 currentWebsiteIssuedToOName = currentWebsiteSslCertificate.issuedTo.oName
67 currentWebsiteIssuedToUName = currentWebsiteSslCertificate.issuedTo.uName
68 currentWebsiteIssuedByCName = currentWebsiteSslCertificate.issuedBy.cName
69 currentWebsiteIssuedByOName = currentWebsiteSslCertificate.issuedBy.oName
70 currentWebsiteIssuedByUName = currentWebsiteSslCertificate.issuedBy.uName
71 currentWebsiteSslStartDate = currentWebsiteSslCertificate.validNotBeforeDate
72 currentWebsiteSslEndDate = currentWebsiteSslCertificate.validNotAfterDate
75 // Get the pinned SSL certificate information if it exists.
76 if (nestedScrollWebView.hasPinnedSslCertificate()) {
77 // Get the pinned SSL certificate.
78 val pinnedSslCertificatePair = nestedScrollWebView.getPinnedSslCertificate()
80 // Extract the arrays from the array list.
81 val pinnedSslCertificateStringArray = pinnedSslCertificatePair.first
82 val pinnedSslCertificateDateArray = pinnedSslCertificatePair.second
84 // Populate the pinned SSL certificate string variables.
85 pinnedSslIssuedToCName = pinnedSslCertificateStringArray[0]
86 pinnedSslIssuedToOName = pinnedSslCertificateStringArray[1]
87 pinnedSslIssuedToUName = pinnedSslCertificateStringArray[2]
88 pinnedSslIssuedByCName = pinnedSslCertificateStringArray[3]
89 pinnedSslIssuedByOName = pinnedSslCertificateStringArray[4]
90 pinnedSslIssuedByUName = pinnedSslCertificateStringArray[5]
92 // Populate the pinned SSL certificate date variables.
93 pinnedSslStartDate = pinnedSslCertificateDateArray[0]
94 pinnedSslEndDate = pinnedSslCertificateDateArray[1]
97 // Initialize string variables to store the SSL certificate dates. Strings are needed to compare the values below, which doesn't work with dates if the first one is null.
98 var currentWebsiteSslStartDateString = ""
99 var currentWebsiteSslEndDateString = ""
100 var pinnedSslStartDateString = ""
101 var pinnedSslEndDateString = ""
103 // Convert the dates to strings if they are not null.
104 if (currentWebsiteSslStartDate != null) {
105 currentWebsiteSslStartDateString = currentWebsiteSslStartDate.toString()
107 if (currentWebsiteSslEndDate != null) {
108 currentWebsiteSslEndDateString = currentWebsiteSslEndDate.toString()
110 if (pinnedSslStartDate != null) {
111 pinnedSslStartDateString = pinnedSslStartDate.toString()
113 if (pinnedSslEndDate != null) {
114 pinnedSslEndDateString = pinnedSslEndDate.toString()
117 // Check to see if the pinned information matches the current information.
118 if (((nestedScrollWebView.pinnedIpAddresses != "") && (nestedScrollWebView.currentIpAddresses != nestedScrollWebView.pinnedIpAddresses)) ||
119 (nestedScrollWebView.hasPinnedSslCertificate() && ((currentWebsiteIssuedToCName != pinnedSslIssuedToCName) ||
120 (currentWebsiteIssuedToOName != pinnedSslIssuedToOName) || (currentWebsiteIssuedToUName != pinnedSslIssuedToUName) ||
121 (currentWebsiteIssuedByCName != pinnedSslIssuedByCName) || (currentWebsiteIssuedByOName != pinnedSslIssuedByOName) ||
122 (currentWebsiteIssuedByUName != pinnedSslIssuedByUName) || (currentWebsiteSslStartDateString != pinnedSslStartDateString) ||
123 (currentWebsiteSslEndDateString != pinnedSslEndDateString)))) {
124 // Get a handle for the pinned mismatch alert dialog.
125 val pinnedMismatchDialogFragment: DialogFragment = displayDialog(nestedScrollWebView.webViewFragmentId)
127 // Try to show the dialog. Sometimes the window is not active.
129 // Show the pinned mismatch alert dialog.
130 pinnedMismatchDialogFragment.show(fragmentManager, activity.getString(R.string.pinned_mismatch))
131 } catch (exception: Exception) {
132 // Add the dialog to the pending dialog array list. It will be displayed in `onStart()`.
133 MainWebViewActivity.pendingDialogsArrayList.add(PendingDialog(pinnedMismatchDialogFragment, activity.getString(R.string.pinned_mismatch)))