[tor-commits] [Git][tpo/applications/firefox-android][firefox-android-115.2.1-13.5-1] Enable the connect assist experiments on alpha
Pier Angelo Vendrame (@pierov)
git at gitlab.torproject.org
Thu Dec 21 21:57:42 UTC 2023
Pier Angelo Vendrame pushed to branch firefox-android-115.2.1-13.5-1 at The Tor Project / Applications / firefox-android
Commits:
48593938 by clairehurst at 2023-12-21T14:48:46-07:00
Enable the connect assist experiments on alpha
- - - - -
13 changed files:
- android-components/components/browser/engine-gecko/src/main/java/mozilla/components/browser/engine/gecko/GeckoEngine.kt
- android-components/components/concept/engine/src/main/java/mozilla/components/concept/engine/Settings.kt
- fenix/app/src/main/java/org/mozilla/fenix/HomeActivity.kt
- fenix/app/src/main/java/org/mozilla/fenix/browser/BaseBrowserFragment.kt
- fenix/app/src/main/java/org/mozilla/fenix/components/Core.kt
- fenix/app/src/main/java/org/mozilla/fenix/settings/TorNetworkSettingsFragment.kt
- + fenix/app/src/main/java/org/mozilla/fenix/tor/TorBetaConnectionFeaturesFragment.kt
- fenix/app/src/main/java/org/mozilla/fenix/tor/TorBootstrapFragment.kt
- fenix/app/src/main/java/org/mozilla/fenix/utils/Settings.kt
- + fenix/app/src/main/res/layout/tor_network_settings_beta_connection_features.xml
- fenix/app/src/main/res/navigation/nav_graph.xml
- fenix/app/src/main/res/values/preference_keys.xml
- fenix/app/src/main/res/xml/tor_network_settings_preferences.xml
Changes:
=====================================
android-components/components/browser/engine-gecko/src/main/java/mozilla/components/browser/engine/gecko/GeckoEngine.kt
=====================================
@@ -799,6 +799,11 @@ class GeckoEngine(
override var prioritizeOnions: Boolean
get() = runtime.settings.prioritizeOnions
set(value) { runtime.settings.prioritizeOnions = value }
+ override var useNewBootstrap: Boolean
+ get() = runtime.settings.useNewBootstrap
+ set(value) {
+ runtime.settings.useNewBootstrap = value
+ }
}.apply {
defaultSettings?.let {
this.javascriptEnabled = it.javascriptEnabled
@@ -824,6 +829,7 @@ class GeckoEngine(
this.torSecurityLevel = it.torSecurityLevel
this.spoofEnglish = it.spoofEnglish
this.prioritizeOnions = it.prioritizeOnions
+ this.useNewBootstrap = it.useNewBootstrap
}
}
@@ -929,6 +935,8 @@ class GeckoEngine(
unBlockedBySmartBlock = this.blockingData.any { it.unBlockedBySmartBlock() },
)
}
+
+ fun getTorIntegrationController() = runtime.getTorIntegrationController()
}
internal fun ContentBlockingController.LogEntry.BlockingData.hasBlockedCookies(): Boolean {
=====================================
android-components/components/concept/engine/src/main/java/mozilla/components/concept/engine/Settings.kt
=====================================
@@ -214,6 +214,8 @@ abstract class Settings {
open var spoofEnglish: Boolean by UnsupportedSetting()
open var prioritizeOnions: Boolean by UnsupportedSetting()
+
+ open var useNewBootstrap: Boolean by UnsupportedSetting()
}
/**
@@ -259,6 +261,7 @@ data class DefaultSettings(
override var torSecurityLevel: Int = 4,
override var spoofEnglish: Boolean = false,
override var prioritizeOnions: Boolean = false,
+ override var useNewBootstrap: Boolean = false,
) : Settings()
class UnsupportedSetting<T> {
=====================================
fenix/app/src/main/java/org/mozilla/fenix/HomeActivity.kt
=====================================
@@ -164,6 +164,11 @@ import org.mozilla.fenix.utils.Settings
import java.lang.ref.WeakReference
import java.util.Locale
+import androidx.navigation.fragment.findNavController
+import mozilla.components.browser.engine.gecko.GeckoEngine
+import mozilla.components.browser.state.selector.findCustomTab
+import org.mozilla.geckoview.TorIntegrationAndroid
+
/**
* The main activity of the application. The application is primarily a single Activity (this one)
* with fragments switching out to display different views. The most important views shown here are the:
@@ -171,7 +176,7 @@ import java.util.Locale
* - browser screen
*/
@SuppressWarnings("TooManyFunctions", "LargeClass", "LongParameterList", "LongMethod")
-open class HomeActivity : LocaleAwareAppCompatActivity(), NavHostActivity {
+open class HomeActivity : LocaleAwareAppCompatActivity(), NavHostActivity, TorIntegrationAndroid.BootstrapStateChangeListener {
// DO NOT MOVE ANYTHING ABOVE THIS, GETTING INIT TIME IS CRITICAL
// we need to store startup timestamp for warm startup. we cant directly store
// inside AppStartupTelemetry since that class lives inside components and
@@ -201,7 +206,7 @@ open class HomeActivity : LocaleAwareAppCompatActivity(), NavHostActivity {
private var inflater: LayoutInflater? = null
- private val navHost by lazy {
+ val navHost by lazy {
supportFragmentManager.findFragmentById(R.id.container) as NavHostFragment
}
@@ -396,6 +401,12 @@ open class HomeActivity : LocaleAwareAppCompatActivity(), NavHostActivity {
components.notificationsDelegate.bindToActivity(this)
+ val engine = components.core.engine
+ if (engine is GeckoEngine) {
+ val torIntegration = engine.getTorIntegrationController()
+ torIntegration.registerBootstrapStateChangeListener(this)
+ }
+
StartupTimeline.onActivityCreateEndHome(this) // DO NOT MOVE ANYTHING BELOW HERE.
}
@@ -609,6 +620,12 @@ open class HomeActivity : LocaleAwareAppCompatActivity(), NavHostActivity {
// underlying Application, as well.
(application as FenixApplication).terminate()
}
+
+ val engine = components.core.engine
+ if (engine is GeckoEngine) {
+ val torIntegration = engine.getTorIntegrationController()
+ torIntegration.unregisterBootstrapStateChangeListener(this)
+ }
}
override fun onConfigurationChanged(newConfig: Configuration) {
@@ -1163,7 +1180,20 @@ open class HomeActivity : LocaleAwareAppCompatActivity(), NavHostActivity {
}
open fun navigateToHome() {
- navHost.navController.navigate(NavGraphDirections.actionStartupTorbootstrap())
+ if (settings().useNewBootstrap) {
+ if (settings().useNewBootstrapNativeUi) {
+ navHost.navController.navigate(NavGraphDirections.actionStartupTorConnectionAssist())
+ } else {
+ navHost.navController.navigate(NavGraphDirections.actionStartupHome())
+ openToBrowserAndLoad(
+ searchTermOrURL = "about:torconnect",
+ newTab = true,
+ from = BrowserDirection.FromHome,
+ )
+ }
+ } else {
+ navHost.navController.navigate(NavGraphDirections.actionStartupTorbootstrap())
+ }
}
override fun attachBaseContext(base: Context) {
@@ -1341,4 +1371,15 @@ open class HomeActivity : LocaleAwareAppCompatActivity(), NavHostActivity {
// telemetry purposes.
const val PWA_RECENTLY_USED_THRESHOLD = DateUtils.DAY_IN_MILLIS * 30L
}
+
+ override fun onBootstrapStateChange(state: String) = Unit
+ override fun onBootstrapProgress(progress: Double, status: String, hasWarnings: Boolean) = Unit
+ override fun onBootstrapComplete() {
+ components.useCases.tabsUseCases.removeAllTabs()
+ navHost.navController.navigate(NavGraphDirections.actionStartupHome())
+ }
+ override fun onBootstrapError(message: String, details: String) = Unit
+ override fun onSettingsRequested() {
+ navHost.navController.navigate(NavGraphDirections.actionGlobalSettingsFragment())
+ }
}
=====================================
fenix/app/src/main/java/org/mozilla/fenix/browser/BaseBrowserFragment.kt
=====================================
@@ -1189,6 +1189,9 @@ abstract class BaseBrowserFragment :
val context = requireContext()
resumeDownloadDialogState(selectedTab.id, context.components.core.store, context, toolbarHeight)
it.announceForAccessibility(selectedTab.toDisplayTitle())
+ if (getCurrentTab()?.content?.url == "about:torconnect") {
+ browserToolbarView.view.visibility = View.GONE
+ }
}
} else {
view?.let { view -> initializeUI(view) }
@@ -1206,6 +1209,24 @@ abstract class BaseBrowserFragment :
components.useCases.sessionUseCases.reload()
}
hideToolbar()
+ handleBetaHtmlTorConnect()
+ }
+
+ private fun handleBetaHtmlTorConnect() {
+ if (getCurrentTab()?.content?.url == "about:torconnect") {
+ if (!requireActivity().settings().useNewBootstrap) {
+ requireContext().components.useCases.tabsUseCases.removeAllTabs()
+ (requireActivity() as HomeActivity).navHost.navController.navigate(
+ NavGraphDirections.actionStartupTorbootstrap(),
+ )
+ } else if (!requireActivity().settings().useNewBootstrapHtmlUi) {
+ requireContext().components.useCases.tabsUseCases.removeAllTabs()
+ (requireActivity() as HomeActivity).navigateToHome()
+ } else {
+ // This just makes it not flash (be visible for a split second) before handleTabSelected() hides it again
+ browserToolbarView.view.visibility = View.GONE
+ }
+ }
}
@CallSuper
=====================================
fenix/app/src/main/java/org/mozilla/fenix/components/Core.kt
=====================================
@@ -146,6 +146,7 @@ class Core(
torSecurityLevel = context.settings().torSecurityLevel().intRepresentation,
spoofEnglish = context.settings().spoofEnglish,
prioritizeOnions = context.settings().prioritizeOnions,
+ useNewBootstrap = context.settings().useNewBootstrap,
)
GeckoEngine(
=====================================
fenix/app/src/main/java/org/mozilla/fenix/settings/TorNetworkSettingsFragment.kt
=====================================
@@ -76,6 +76,15 @@ class TorNetworkSettingsFragment : PreferenceFragmentCompat(), TorEvents {
}
}
+ requirePreference<Preference>(R.string.pref_key_use_new_bootstrap).apply {
+ setOnPreferenceClickListener {
+ val directions =
+ TorNetworkSettingsFragmentDirections.actionTorNetworkSettingsFragmentToBetaConnectionFeaturesFragment()
+ requireView().findNavController().navigate(directions)
+ true
+ }
+ }
+
setStatus()
}
=====================================
fenix/app/src/main/java/org/mozilla/fenix/tor/TorBetaConnectionFeaturesFragment.kt
=====================================
@@ -0,0 +1,69 @@
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+package org.mozilla.fenix.tor
+
+import android.os.Bundle
+import android.view.LayoutInflater
+import android.view.View
+import android.view.ViewGroup
+import androidx.core.view.children
+import androidx.fragment.app.Fragment
+import org.mozilla.fenix.databinding.TorNetworkSettingsBetaConnectionFeaturesBinding
+import org.mozilla.fenix.ext.components
+import org.mozilla.fenix.ext.settings
+
+/**
+ * Lets the user customize beta connection features mode.
+ */
+class TorBetaConnectionFeaturesFragment : Fragment() {
+ override fun onCreateView(
+ inflater: LayoutInflater,
+ container: ViewGroup?,
+ savedInstanceState: Bundle?,
+ ): View {
+ val binding = TorNetworkSettingsBetaConnectionFeaturesBinding.inflate(inflater)
+
+ binding.enableBetaConnectionFeaturesSwitch.run {
+ isChecked = context.settings().useNewBootstrap
+ setConnectionAssistUI(binding, isChecked)
+
+ setOnCheckedChangeListener { _, isConnectionAssistEnabled ->
+ context.settings().useNewBootstrap = isConnectionAssistEnabled
+ setConnectionAssistUI(binding, isConnectionAssistEnabled)
+ updateEngineConnectionAssistMode()
+ }
+ }
+
+ // Since the beta connection features modes are in a RadioGroup we only need one listener to know of all their changes.
+ binding.useNewBootstrapWithNativeUiRadioButton.setOnCheckedChangeListener { _, _ ->
+ updateEngineConnectionAssistMode()
+ }
+
+ return binding.root
+ }
+
+ private fun setConnectionAssistUI(
+ binding: TorNetworkSettingsBetaConnectionFeaturesBinding,
+ isBetaConnectionAssistEnabled: Boolean,
+ ) {
+ if (!isBetaConnectionAssistEnabled) {
+ binding.enableBetaConnectionFeaturesModes.apply {
+ clearCheck()
+ children.forEach { it.isEnabled = false }
+ }
+ } else {
+ // Do not enable the native UI until it is actually available.
+ // binding.enableBetaConnectionFeaturesModes.children.forEach { it.isEnabled = true }
+ binding.useNewBootstrapWithHtmlUiRadioButton.isEnabled = true
+ binding.useNewBootstrapWithNativeUiRadioButton.isEnabled = false
+ }
+ }
+
+ private fun updateEngineConnectionAssistMode() {
+ requireContext().components.core.engine.settings.useNewBootstrap =
+ requireContext().settings().useNewBootstrap
+ }
+
+}
=====================================
fenix/app/src/main/java/org/mozilla/fenix/tor/TorBootstrapFragment.kt
=====================================
@@ -20,8 +20,10 @@ import org.mozilla.fenix.tor.interactor.DefaultTorBootstrapInteractor
import org.mozilla.fenix.tor.interactor.TorBootstrapInteractor
import androidx.navigation.fragment.findNavController
import com.google.android.material.appbar.AppBarLayout
+import org.mozilla.fenix.HomeActivity
import org.mozilla.fenix.ext.components
import org.mozilla.fenix.ext.hideToolbar
+import org.mozilla.fenix.ext.settings
import org.mozilla.fenix.tor.controller.DefaultTorBootstrapController
import org.mozilla.fenix.tor.view.TorBootstrapView
@@ -169,6 +171,9 @@ class TorBootstrapFragment : Fragment() {
// triggered to cause an automatic update on warm start (no tab selection occurs). So we
// update it manually here.
requireComponents.useCases.sessionUseCases.updateLastAccess()
+ if (requireContext().settings().useNewBootstrap){
+ (requireActivity() as HomeActivity).navigateToHome()
+ }
}
private fun handleTorBootstrapConnect() {
=====================================
fenix/app/src/main/java/org/mozilla/fenix/utils/Settings.kt
=====================================
@@ -1859,4 +1859,19 @@ class Settings(private val appContext: Context) : PreferencesHolder {
* Indicates if the new Search settings UI is enabled.
*/
var enableUnifiedSearchSettingsUI: Boolean = showUnifiedSearchFeature && FeatureFlags.unifiedSearchSettings
+
+ var useNewBootstrap by booleanPreference(
+ appContext.getPreferenceKey(R.string.pref_key_use_new_bootstrap),
+ default = false,
+ )
+
+ var useNewBootstrapNativeUi by booleanPreference(
+ appContext.getPreferenceKey(R.string.pref_key_use_new_bootstrap_with_android_native),
+ default = false,
+ )
+
+ var useNewBootstrapHtmlUi by booleanPreference(
+ appContext.getPreferenceKey(R.string.pref_key_use_new_bootstrap_with_html),
+ default = true
+ )
}
=====================================
fenix/app/src/main/res/layout/tor_network_settings_beta_connection_features.xml
=====================================
@@ -0,0 +1,100 @@
+<?xml version="1.0" encoding="utf-8"?><!-- This Source Code Form is subject to the terms of the Mozilla Public
+ - License, v. 2.0. If a copy of the MPL was not distributed with this
+ - file, You can obtain one at http://mozilla.org/MPL/2.0/. -->
+<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:app="http://schemas.android.com/apk/res-auto"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content">
+
+ <TextView
+ android:id="@+id/enable_beta_connection_features_title"
+ android:layout_width="0dp"
+ android:layout_height="wrap_content"
+ android:layout_marginStart="16dp"
+ android:layout_marginTop="16dp"
+ android:layout_marginBottom="2dp"
+ android:clickable="false"
+ android:text="Enable beta connection features"
+ android:textAppearance="@style/ListItemTextStyle"
+ android:textSize="16sp"
+ app:layout_constraintBottom_toTopOf="@id/enable_beta_connection_features_summary"
+ app:layout_constraintEnd_toStartOf="@id/enable_beta_connection_features_switch"
+ app:layout_constraintStart_toStartOf="parent"
+ app:layout_constraintTop_toTopOf="parent"
+ app:lineHeight="24.sp" />
+
+ <TextView
+ android:id="@+id/enable_beta_connection_features_summary"
+ android:layout_width="0dp"
+ android:layout_height="wrap_content"
+ android:text="Help us test our new connection assist features which focuses on a streamlined connection with better integration with bridges"
+ android:textColor="?attr/textSecondary"
+ android:textColorLink="?attr/textSecondary"
+ android:textSize="12sp"
+ app:layout_constraintBottom_toTopOf="@id/enable_beta_connection_features_modes"
+ app:layout_constraintEnd_toEndOf="@id/enable_beta_connection_features_title"
+ app:layout_constraintStart_toStartOf="@id/enable_beta_connection_features_title"
+ app:layout_constraintTop_toBottomOf="@id/enable_beta_connection_features_title"
+ app:lineHeight="16.sp" />
+
+ <androidx.appcompat.widget.SwitchCompat
+ android:id="@+id/enable_beta_connection_features_switch"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:minHeight="48dp"
+ android:paddingStart="18dp"
+ android:paddingEnd="18dp"
+ android:textColor="@color/state_list_text_color"
+ android:textOff="@string/studies_off"
+ android:textOn="@string/studies_on"
+ app:layout_constraintEnd_toEndOf="parent"
+ app:layout_constraintTop_toTopOf="@id/enable_beta_connection_features_title" />
+
+ <RadioGroup
+ android:id="@+id/enable_beta_connection_features_modes"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:layout_marginTop="10dp"
+ app:layout_constraintEnd_toEndOf="parent"
+ app:layout_constraintStart_toStartOf="parent"
+ app:layout_constraintTop_toBottomOf="@id/enable_beta_connection_features_summary">
+
+ <org.mozilla.fenix.settings.PreferenceBackedRadioButton
+ android:id="@+id/use_new_bootstrap_with_html_ui_radio_button"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:background="?android:attr/selectableItemBackground"
+ android:button="@null"
+ android:drawablePadding="@dimen/radio_button_preference_drawable_padding"
+ android:paddingStart="@dimen/radio_button_preference_horizontal"
+ android:paddingTop="@dimen/radio_button_preference_vertical"
+ android:paddingEnd="@dimen/radio_button_preference_horizontal"
+ android:paddingBottom="@dimen/radio_button_preference_vertical"
+ android:text="HTML UI"
+ android:textAppearance="?android:attr/textAppearanceListItem"
+ android:textSize="16sp"
+ app:drawableStartCompat="?android:attr/listChoiceIndicatorSingle"
+ app:preferenceKey="@string/pref_key_use_new_bootstrap_with_html"
+ app:preferenceKeyDefaultValue="true" />
+
+ <org.mozilla.fenix.settings.PreferenceBackedRadioButton
+ android:id="@+id/use_new_bootstrap_with_native_ui_radio_button"
+ android:layout_width="match_parent"
+ android:layout_height="48dp"
+ android:background="?android:attr/selectableItemBackground"
+ android:button="@null"
+ android:drawablePadding="@dimen/radio_button_preference_drawable_padding"
+ android:enabled="false"
+ android:paddingStart="@dimen/radio_button_preference_horizontal"
+ android:paddingTop="@dimen/radio_button_preference_vertical"
+ android:paddingEnd="@dimen/radio_button_preference_horizontal"
+ android:paddingBottom="@dimen/radio_button_preference_vertical"
+ android:text="Native Android UI"
+ android:textAppearance="?android:attr/textAppearanceListItem"
+ android:textSize="16sp"
+ app:drawableStartCompat="?android:attr/listChoiceIndicatorSingle"
+ app:preferenceKey="@string/pref_key_use_new_bootstrap_with_android_native"
+ app:preferenceKeyDefaultValue="false" />
+ </RadioGroup>
+
+</androidx.constraintlayout.widget.ConstraintLayout>
=====================================
fenix/app/src/main/res/navigation/nav_graph.xml
=====================================
@@ -27,6 +27,12 @@
app:popUpTo="@id/startupFragment"
app:popUpToInclusive="true" />
+ <action
+ android:id="@+id/action_startup_tor_connection_assist"
+ app:destination="@+id/torConnectionAssistFragment"
+ app:popUpTo="@id/startupFragment"
+ app:popUpToInclusive="true" />
+
<action
android:id="@+id/action_global_home"
app:destination="@id/homeFragment"
@@ -941,12 +947,25 @@
app:exitAnim="@anim/slide_out_left"
app:popEnterAnim="@anim/slide_in_left"
app:popExitAnim="@anim/slide_out_right" />
+ <action
+ android:id="@+id/action_torNetworkSettingsFragment_to_BetaConnectionFeaturesFragment"
+ app:destination="@+id/torBetaConnectionFeaturesFragment"
+ app:enterAnim="@anim/slide_in_right"
+ app:exitAnim="@anim/slide_out_left"
+ app:popEnterAnim="@anim/slide_in_left"
+ app:popExitAnim="@anim/slide_out_right" />
</fragment>
<fragment
android:id="@+id/torBridgeConfigFragment"
android:name="org.mozilla.fenix.settings.TorBridgeConfigFragment"
android:label="@string/preferences_tor_network_settings_bridge_config"
tools:layout="@layout/fragment_tor_bridge_config" />
+ <fragment
+ android:id="@+id/torBetaConnectionFeaturesFragment"
+ android:name="org.mozilla.fenix.tor.TorBetaConnectionFeaturesFragment"
+ android:label="Enable beta connection features"
+ tools:layout="@layout/tor_network_settings_beta_connection_features" />
+
<fragment
android:id="@+id/trackingProtectionFragment"
android:name="org.mozilla.fenix.settings.TrackingProtectionFragment">
=====================================
fenix/app/src/main/res/values/preference_keys.xml
=====================================
@@ -376,6 +376,9 @@
<string name="pref_key_tor_network_settings" translatable="false">pref_key_tor_network_settings</string>
<string name="pref_key_tor_network_settings_explanation" translatable="false">pref_key_tor_network_settings_explanation</string>
<string name="pref_key_tor_network_settings_bridge_config" translatable="false">pref_key_tor_network_settings_bridge_config</string>
+ <string name="pref_key_use_new_bootstrap" translatable="false">pref_key_use_new_bootstrap</string>
+ <string name="pref_key_use_new_bootstrap_with_android_native" translatable="false">pref_key_use_new_bootstrap_with_android_native</string>
+ <string name="pref_key_use_new_bootstrap_with_html" translatable="false">pref_key_use_new_bootstrap_with_html</string>
<string name="pref_key_tor_network_settings_bridge_config_explanation" translatable="false">pref_key_tor_network_settings_bridge_config_explanation</string>
<string name="pref_key_tor_network_settings_bridge_config_toggle" translatable="false">pref_key_tor_network_settings_bridge_config_toggle</string>
<string name="pref_key_tor_network_settings_bridge_config_builtin_bridge_obfs4" translatable="false">pref_key_tor_network_settings_bridge_config_builtin_bridge_obfs4</string>
=====================================
fenix/app/src/main/res/xml/tor_network_settings_preferences.xml
=====================================
@@ -27,4 +27,9 @@
android:title="@string/preferences_tor_network_settings_bridge_config"
android:summary="@string/preferences_tor_network_settings_bridge_config_description"
app:allowDividerAbove="true" />
+ <Preference
+ android:key="@string/pref_key_use_new_bootstrap"
+ android:title="Enable beta connection features"
+ app:allowDividerAbove="true" />
+
</androidx.preference.PreferenceScreen>
View it on GitLab: https://gitlab.torproject.org/tpo/applications/firefox-android/-/commit/48593938fafff1345fc8e131caa59c48a892b171
--
View it on GitLab: https://gitlab.torproject.org/tpo/applications/firefox-android/-/commit/48593938fafff1345fc8e131caa59c48a892b171
You're receiving this email because of your account on gitlab.torproject.org.
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://lists.torproject.org/pipermail/tor-commits/attachments/20231221/11353a72/attachment-0001.htm>
More information about the tor-commits
mailing list