tor-browser

The Tor Browser
git clone https://git.dasho.dev/tor-browser.git
Log | Files | Refs | README | LICENSE

commit 3225a787fef10e7f338a2bc527299c369b930414
parent 4e5864a4ee8e7ab48f55d3495836f508809a3657
Author: Dana Keeler <dkeeler@mozilla.com>
Date:   Fri, 19 Dec 2025 20:13:50 +0000

Bug 1985309 - use certificate viewer in fenix r=android-reviewers,petru

Differential Revision: https://phabricator.services.mozilla.com/D276043

Diffstat:
Mmobile/android/fenix/app/src/main/java/org/mozilla/fenix/browser/BrowserFragment.kt | 2+-
Mmobile/android/fenix/app/src/main/java/org/mozilla/fenix/components/toolbar/BrowserToolbarMiddleware.kt | 2+-
Mmobile/android/fenix/app/src/main/java/org/mozilla/fenix/components/toolbar/CustomTabBrowserToolbarMiddleware.kt | 2+-
Mmobile/android/fenix/app/src/main/java/org/mozilla/fenix/customtabs/ExternalAppBrowserFragment.kt | 2+-
Mmobile/android/fenix/app/src/main/java/org/mozilla/fenix/settings/trustpanel/TrustPanelFragment.kt | 21+++++++++++++++++++--
Mmobile/android/fenix/app/src/main/java/org/mozilla/fenix/settings/trustpanel/store/TrustPanelState.kt | 9++++++---
Mmobile/android/fenix/app/src/main/java/org/mozilla/fenix/settings/trustpanel/ui/ProtectionPanel.kt | 6+++++-
Mmobile/android/fenix/app/src/main/java/org/mozilla/fenix/settings/trustpanel/ui/ProtectionPanelHeader.kt | 6+++---
Mmobile/android/fenix/app/src/main/res/navigation/nav_graph.xml | 12++++++------
9 files changed, 43 insertions(+), 19 deletions(-)

diff --git a/mobile/android/fenix/app/src/main/java/org/mozilla/fenix/browser/BrowserFragment.kt b/mobile/android/fenix/app/src/main/java/org/mozilla/fenix/browser/BrowserFragment.kt @@ -637,7 +637,7 @@ class BrowserFragment : BaseBrowserFragment(), UserInteractionHandler { isLocalPdf = tab.content.url.isContentUrl(), isSecured = tab.content.securityInfo.isSecure, sitePermissions = sitePermissions, - certificateName = tab.content.securityInfo.issuer, + certificate = tab.content.securityInfo.certificate, permissionHighlights = tab.content.permissionHighlights, isTrackingProtectionEnabled = isTrackingProtectionEnabled, cookieBannerUIMode = cookieBannerUIMode, diff --git a/mobile/android/fenix/app/src/main/java/org/mozilla/fenix/components/toolbar/BrowserToolbarMiddleware.kt b/mobile/android/fenix/app/src/main/java/org/mozilla/fenix/components/toolbar/BrowserToolbarMiddleware.kt @@ -630,7 +630,7 @@ class BrowserToolbarMiddleware( isLocalPdf = tab.content.url.isContentUrl(), isSecured = tab.content.securityInfo.isSecure, sitePermissions = sitePermissions, - certificateName = tab.content.securityInfo.issuer, + certificate = tab.content.securityInfo.certificate, permissionHighlights = tab.content.permissionHighlights, isTrackingProtectionEnabled = isTrackingProtectionEnabled, cookieBannerUIMode = cookieBannerUIMode, diff --git a/mobile/android/fenix/app/src/main/java/org/mozilla/fenix/components/toolbar/CustomTabBrowserToolbarMiddleware.kt b/mobile/android/fenix/app/src/main/java/org/mozilla/fenix/components/toolbar/CustomTabBrowserToolbarMiddleware.kt @@ -192,7 +192,7 @@ class CustomTabBrowserToolbarMiddleware( isLocalPdf = customTab.content.url.isContentUrl(), isSecured = customTab.content.securityInfo.isSecure, sitePermissions = sitePermissions, - certificateName = customTab.content.securityInfo.issuer, + certificate = customTab.content.securityInfo.certificate, permissionHighlights = customTab.content.permissionHighlights, isTrackingProtectionEnabled = customTab.trackingProtection.enabled && !isExcepted, diff --git a/mobile/android/fenix/app/src/main/java/org/mozilla/fenix/customtabs/ExternalAppBrowserFragment.kt b/mobile/android/fenix/app/src/main/java/org/mozilla/fenix/customtabs/ExternalAppBrowserFragment.kt @@ -208,7 +208,7 @@ class ExternalAppBrowserFragment : BaseBrowserFragment() { isLocalPdf = tab.content.url.isContentUrl(), isSecured = tab.content.securityInfo.isSecure, sitePermissions = sitePermissions, - certificateName = tab.content.securityInfo.issuer, + certificate = tab.content.securityInfo.certificate, permissionHighlights = tab.content.permissionHighlights, isTrackingProtectionEnabled = tab.trackingProtection.enabled && !contains, cookieBannerUIMode = cookieBannerUIMode, diff --git a/mobile/android/fenix/app/src/main/java/org/mozilla/fenix/settings/trustpanel/TrustPanelFragment.kt b/mobile/android/fenix/app/src/main/java/org/mozilla/fenix/settings/trustpanel/TrustPanelFragment.kt @@ -8,6 +8,7 @@ import android.app.Dialog import android.content.Intent import android.net.Uri import android.os.Bundle +import android.util.Base64 import android.view.LayoutInflater import android.view.ViewGroup import android.widget.FrameLayout @@ -51,8 +52,11 @@ import mozilla.components.support.ktx.kotlinx.coroutines.flow.ifAnyChanged import org.mozilla.fenix.BuildConfig import org.mozilla.fenix.HomeActivity import org.mozilla.fenix.R +import org.mozilla.fenix.browser.browsingmode.BrowsingModeManager import org.mozilla.fenix.components.components import org.mozilla.fenix.components.menu.compose.MenuDialogBottomSheet +import org.mozilla.fenix.ext.openToBrowser +import org.mozilla.fenix.ext.requireComponents import org.mozilla.fenix.settings.PhoneFeature import org.mozilla.fenix.settings.trustpanel.middleware.TrustPanelMiddleware import org.mozilla.fenix.settings.trustpanel.middleware.TrustPanelNavigationMiddleware @@ -90,11 +94,13 @@ class TrustPanelFragment : BottomSheetDialogFragment() { ActivityResultContracts.RequestMultiplePermissions(), ) { isGranted: Map<String, Boolean> -> permissionsCallback.invoke(isGranted) } + private lateinit var browsingModeManager: BrowsingModeManager + override fun onCreateDialog(savedInstanceState: Bundle?): Dialog = (super.onCreateDialog(savedInstanceState) as BottomSheetDialog).apply { setOnShowListener { val safeActivity = activity ?: return@setOnShowListener - val browsingModeManager = (safeActivity as HomeActivity).browsingModeManager + browsingModeManager = (safeActivity as HomeActivity).browsingModeManager val navigationBarColor = if (browsingModeManager.mode.isPrivate) { ContextCompat.getColor(context, R.color.fx_mobile_private_layer_color_3) @@ -130,7 +136,7 @@ class TrustPanelFragment : BottomSheetDialogFragment() { isSecured = args.isSecured, websiteUrl = args.url, websiteTitle = args.title, - certificateName = args.certificateName, + certificate = args.certificate, ), sessionState = components.core.store.state.findTabOrCustomTab(args.sessionId), settings = settings, @@ -285,6 +291,17 @@ class TrustPanelFragment : BottomSheetDialogFragment() { onToggleablePermissionClick = { websitePermission: WebsitePermission.Toggleable -> store.dispatch(TrustPanelAction.TogglePermission(websitePermission)) }, + onViewCertificateClick = { certificate -> + val bytes = certificate.getEncoded() + val base64 = Base64.encodeToString(bytes, Base64.NO_WRAP or Base64.NO_PADDING) + findNavController().openToBrowser() + requireComponents.useCases.tabsUseCases.addTab( + "about:certificate?cert=${Uri.encode(base64)}", + parentId = sessionState?.id, + contextId = sessionState?.contextId, + private = browsingModeManager.mode.isPrivate, + ) + }, ) } diff --git a/mobile/android/fenix/app/src/main/java/org/mozilla/fenix/settings/trustpanel/store/TrustPanelState.kt b/mobile/android/fenix/app/src/main/java/org/mozilla/fenix/settings/trustpanel/store/TrustPanelState.kt @@ -13,6 +13,7 @@ import org.mozilla.fenix.R import org.mozilla.fenix.settings.PhoneFeature import org.mozilla.fenix.trackingprotection.TrackerBuckets import org.mozilla.fenix.trackingprotection.TrackingProtectionCategory +import java.security.cert.X509Certificate typealias WebsitePermissionsState = Map<PhoneFeature, WebsitePermission> @@ -49,14 +50,16 @@ data class TrustPanelState( * @property isSecured Whether the website connection is secured or not. * @property websiteUrl The URL of the current web page. * @property websiteTitle The title of the current web page. - * @property certificateName the certificate name of the current web page. + * @property certificate The certificate presented by the current web page. */ data class WebsiteInfoState( val isSecured: Boolean = true, val websiteUrl: String = "", val websiteTitle: String = "", - val certificateName: String = "", -) + val certificate: X509Certificate? = null, +) { + val certificateName: String = certificate?.issuerDN?.name?.substringAfterLast("O=")?.substringBeforeLast(",C=") ?: "" +} /** * Wrapper over a website permission encompassing all its needed state to be rendered on the screen. diff --git a/mobile/android/fenix/app/src/main/java/org/mozilla/fenix/settings/trustpanel/ui/ProtectionPanel.kt b/mobile/android/fenix/app/src/main/java/org/mozilla/fenix/settings/trustpanel/ui/ProtectionPanel.kt @@ -64,6 +64,7 @@ import org.mozilla.fenix.settings.trustpanel.store.AutoplayValue import org.mozilla.fenix.settings.trustpanel.store.WebsiteInfoState import org.mozilla.fenix.settings.trustpanel.store.WebsitePermission import org.mozilla.fenix.theme.FirefoxTheme +import java.security.cert.X509Certificate import mozilla.components.ui.icons.R as iconsR private val BANNER_ROUNDED_CORNER_SHAPE = RoundedCornerShape( @@ -91,6 +92,7 @@ internal fun ProtectionPanel( onPrivacySecuritySettingsClick: () -> Unit, onAutoplayValueClick: (AutoplayValue) -> Unit, onToggleablePermissionClick: (WebsitePermission.Toggleable) -> Unit, + onViewCertificateClick: (X509Certificate) -> Unit, ) { val isSiteProtectionEnabled = isTrackingProtectionEnabled && isGlobalTrackingProtectionEnabled MenuScaffold( @@ -165,6 +167,7 @@ internal fun ProtectionPanel( id = R.string.connection_security_panel_verified_by, websiteInfoState.certificateName, ), + onClick = { websiteInfoState.certificate?.let { onViewCertificateClick(it) } }, ) } else { MenuItem( @@ -443,7 +446,7 @@ private fun ProtectionPanelPreview() { isSecured = true, websiteUrl = "https://www.mozilla.org", websiteTitle = "Mozilla", - certificateName = "", + certificate = null, ), icon = null, isTrackingProtectionEnabled = true, @@ -463,6 +466,7 @@ private fun ProtectionPanelPreview() { onPrivacySecuritySettingsClick = {}, onAutoplayValueClick = {}, onToggleablePermissionClick = {}, + onViewCertificateClick = {}, ) } } diff --git a/mobile/android/fenix/app/src/main/java/org/mozilla/fenix/settings/trustpanel/ui/ProtectionPanelHeader.kt b/mobile/android/fenix/app/src/main/java/org/mozilla/fenix/settings/trustpanel/ui/ProtectionPanelHeader.kt @@ -128,7 +128,7 @@ private fun ProtectionPanelHeaderPreview() { isSecured = true, websiteUrl = "https://www.mozilla.org", websiteTitle = "Mozilla", - certificateName = "", + certificate = null, ), icon = null, modifier = Modifier.background(color = MaterialTheme.colorScheme.surface), @@ -145,7 +145,7 @@ private fun ProtectionPanelHeaderUrlAsTitlePreview() { isSecured = true, websiteUrl = "https://www.mozilla.org", websiteTitle = "", - certificateName = "", + certificate = null, ), icon = null, modifier = Modifier.background(color = MaterialTheme.colorScheme.surface), @@ -162,7 +162,7 @@ private fun ProtectionPanelHeaderPrivatePreview() { isSecured = false, websiteUrl = "https://www.mozilla.org", websiteTitle = "Mozilla", - certificateName = "", + certificate = null, ), icon = null, modifier = Modifier.background(color = MaterialTheme.colorScheme.surface), diff --git a/mobile/android/fenix/app/src/main/res/navigation/nav_graph.xml b/mobile/android/fenix/app/src/main/res/navigation/nav_graph.xml @@ -1838,9 +1838,9 @@ app:argType="mozilla.components.concept.engine.permission.SitePermissions" app:nullable="true" /> <argument - android:name="certificateName" - android:defaultValue=" " - app:argType="string" /> + android:name="certificate" + app:argType="java.security.cert.X509Certificate" + app:nullable="true" /> <argument android:name="permissionHighlights" app:argType="mozilla.components.browser.state.state.content.PermissionHighlightsState" /> @@ -1873,9 +1873,9 @@ app:argType="mozilla.components.concept.engine.permission.SitePermissions" app:nullable="true" /> <argument - android:name="certificateName" - android:defaultValue=" " - app:argType="string" /> + android:name="certificate" + app:argType="java.security.cert.X509Certificate" + app:nullable="true" /> <argument android:name="permissionHighlights" app:argType="mozilla.components.browser.state.state.content.PermissionHighlightsState" />