Skip to content
Snippets Groups Projects
Commit f94bb1f6 authored by Matthew Finkel's avatar Matthew Finkel Committed by Pier Angelo Vendrame
Browse files

TB 40026 [android]: Implement Security Level settings on Android.

Originally, fenix#40026.
parent 79fb2191
Branches
Tags
1 merge request!1500TB 43415: Rebased onto 134.0a1
Showing
with 243 additions and 0 deletions
......@@ -1364,6 +1364,14 @@ class GeckoEngine(
get() = runtime.settings.userCharacteristicPingCurrentVersion
set(value) { runtime.settings.setUserCharacteristicPingCurrentVersion(value) }
override var torSecurityLevel: Int
get() = runtime.settings.torSecurityLevel
set(value) {
value.let {
runtime.settings.torSecurityLevel = it
}
}
override var spoofEnglish: Boolean
get() = runtime.settings.spoofEnglish
set(value) {
......@@ -1425,6 +1433,7 @@ class GeckoEngine(
this.fdlibmMathEnabled = it.fdlibmMathEnabled
this.emailTrackerBlockingPrivateBrowsing = it.emailTrackerBlockingPrivateBrowsing
this.userCharacteristicPingCurrentVersion = it.userCharacteristicPingCurrentVersion
this.torSecurityLevel = it.torSecurityLevel
this.spoofEnglish = it.spoofEnglish
this.webContentIsolationStrategy = it.webContentIsolationStrategy
this.fetchPriorityEnabled = it.fetchPriorityEnabled
......
......@@ -280,6 +280,11 @@ abstract class Settings {
*/
open var userCharacteristicPingCurrentVersion: Int by UnsupportedSetting()
/**
* Setting to control the current security level
*/
open var torSecurityLevel: Int by UnsupportedSetting()
open var spoofEnglish: Boolean by UnsupportedSetting()
/**
......@@ -366,6 +371,7 @@ data class DefaultSettings(
override var queryParameterStrippingStripList: String = "",
override var emailTrackerBlockingPrivateBrowsing: Boolean = false,
override var userCharacteristicPingCurrentVersion: Int = 0,
override var torSecurityLevel: Int = 4,
override var spoofEnglish: Boolean = false,
override var webContentIsolationStrategy: WebContentIsolationStrategy? =
WebContentIsolationStrategy.ISOLATE_HIGH_VALUE,
......
......@@ -174,6 +174,7 @@ class Core(
cookieBannerHandlingGlobalRulesSubFrames = context.settings().shouldEnableCookieBannerGlobalRulesSubFrame,
emailTrackerBlockingPrivateBrowsing = false,
userCharacteristicPingCurrentVersion = FxNimbus.features.userCharacteristics.value().currentVersion,
torSecurityLevel = context.settings().torSecurityLevel().intRepresentation,
spoofEnglish = context.settings().spoofEnglish,
getDesktopMode = {
store.state.desktopMode
......
......@@ -68,6 +68,7 @@ import org.mozilla.fenix.perf.ProfilerViewModel
import org.mozilla.fenix.settings.account.AccountUiView
import org.mozilla.fenix.snackbar.FenixSnackbarDelegate
import org.mozilla.fenix.snackbar.SnackbarBinding
import org.mozilla.fenix.tor.SecurityLevel
import org.mozilla.fenix.utils.Settings
import kotlin.system.exitProcess
import org.mozilla.fenix.GleanMetrics.Settings as SettingsMetrics
......@@ -363,6 +364,10 @@ class SettingsFragment : PreferenceFragmentCompat() {
SettingsFragmentDirections.actionSettingsFragmentToPrivateBrowsingFragment()
}
resources.getString(R.string.pref_key_tor_security_level_settings) -> {
SettingsFragmentDirections.actionSettingsFragmentToTorSecurityLevelFragment()
}
resources.getString(R.string.pref_key_https_only_settings) -> {
SettingsFragmentDirections.actionSettingsFragmentToHttpsOnlyFragment()
}
......@@ -573,6 +578,7 @@ class SettingsFragment : PreferenceFragmentCompat() {
setupAmoCollectionOverridePreference(requireContext().settings())
setupGeckoLogsPreference(requireContext().settings())
setupAllowDomesticChinaFxaServerPreference()
setupSecurityLevelPreference()
setupHttpsOnlyPreferences()
setupNotificationPreference()
setupSearchPreference()
......@@ -787,6 +793,19 @@ class SettingsFragment : PreferenceFragmentCompat() {
}
}
@VisibleForTesting
internal fun setupSecurityLevelPreference() {
val securityLevelPreference =
requirePreference<Preference>(R.string.pref_key_tor_security_level_settings)
securityLevelPreference.summary = context?.settings()?.torSecurityLevel()?.let {
when (it) {
SecurityLevel.STANDARD -> getString(R.string.tor_security_level_standard_option)
SecurityLevel.SAFER -> getString(R.string.tor_security_level_safer_option)
SecurityLevel.SAFEST -> getString(R.string.tor_security_level_safest_option)
}
}
}
@VisibleForTesting
internal fun setupHttpsOnlyPreferences() {
val httpsOnlyPreference =
......
/* 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.settings
import android.os.Bundle
import androidx.preference.PreferenceFragmentCompat
import org.mozilla.fenix.R
import org.mozilla.fenix.ext.components
import org.mozilla.fenix.ext.settings
import org.mozilla.fenix.ext.showToolbar
import org.mozilla.fenix.tor.SecurityLevel
import org.mozilla.fenix.tor.SecurityLevelUtil
import org.mozilla.fenix.utils.view.GroupableRadioButton
import org.mozilla.fenix.utils.view.addToRadioGroup
import org.mozilla.fenix.utils.view.uncheckAll
/**
* Lets the user choose their security level
*/
@Suppress("SpreadOperator")
class TorSecurityLevelFragment : PreferenceFragmentCompat() {
private val securityLevelRadioGroups = mutableListOf<GroupableRadioButton>()
private var previousSecurityLevel: SecurityLevel? = null
override fun onCreatePreferences(savedInstanceState: Bundle?, rootKey: String?) {
setPreferencesFromResource(R.xml.tor_security_level_preferences, rootKey)
val currentLevel: SecurityLevel? = context?.components?.let {
try {
SecurityLevelUtil.getSecurityLevelFromInt(
it.core.engine.settings.torSecurityLevel
)
} catch (e: IllegalStateException) {
// The default state is 0. If we get an invalid state then
// default to Standard (4).
SecurityLevel.STANDARD
}
}
if (currentLevel == null) {
throw IllegalStateException("context or Components is null.")
}
val radioSafer = bindSecurityLevelRadio(SecurityLevel.SAFER)
val radioSafest = bindSecurityLevelRadio(SecurityLevel.SAFEST)
val radioStandard = bindSecurityLevelRadio(SecurityLevel.STANDARD)
securityLevelRadioGroups.addAll(mutableListOf(radioSafer, radioSafest, radioStandard))
// `*` is Kotlin's "spread" operator, for expanding an Array as a vararg.
addToRadioGroup(*securityLevelRadioGroups.toTypedArray())
securityLevelRadioGroups.uncheckAll()
val securityLevelRadioButton = requirePreference<RadioButtonPreference>(currentLevel.preferenceKey)
// Cache this for later comparison in the OnPreferenceChangeListener
previousSecurityLevel = currentLevel
securityLevelRadioButton.setCheckedWithoutClickListener(true)
}
private fun bindSecurityLevelRadio(
level: SecurityLevel
): RadioButtonPreference {
val radio = requirePreference<RadioButtonPreference>(level.preferenceKey)
radio.summary = getString(level.contentDescriptionRes)
radio.apply {
setOnPreferenceChangeListener<Boolean> { preference, isChecked ->
if (isChecked && (previousSecurityLevel!! != level)) {
preference.context.components.core.engine.settings.torSecurityLevel =
level.intRepresentation
previousSecurityLevel = level
}
true
}
}
return radio
}
}
/* 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.Parcelable
import androidx.annotation.StringRes
import kotlinx.parcelize.Parcelize
import org.mozilla.fenix.R
const val SECURITY_LEVEL_STANDARD = 4
const val SECURITY_LEVEL_SAFER = 2
const val SECURITY_LEVEL_SAFEST = 1
@Parcelize
enum class SecurityLevel(
@StringRes val preferenceKey: Int,
@StringRes val contentDescriptionRes: Int,
val intRepresentation: Int
) : Parcelable {
STANDARD(
preferenceKey = R.string.pref_key_tor_security_level_standard_option,
contentDescriptionRes = R.string.tor_security_level_standard_description,
intRepresentation = SECURITY_LEVEL_STANDARD
),
SAFER(
preferenceKey = R.string.pref_key_tor_security_level_safer_option,
contentDescriptionRes = R.string.tor_security_level_safer_description,
intRepresentation = SECURITY_LEVEL_SAFER
),
SAFEST(
preferenceKey = R.string.pref_key_tor_security_level_safest_option,
contentDescriptionRes = R.string.tor_security_level_safest_description,
intRepresentation = SECURITY_LEVEL_SAFEST
);
}
object SecurityLevelUtil {
fun getSecurityLevelFromInt(level: Int): SecurityLevel {
return when (level) {
SECURITY_LEVEL_STANDARD -> SecurityLevel.STANDARD
SECURITY_LEVEL_SAFER -> SecurityLevel.SAFER
SECURITY_LEVEL_SAFEST -> SecurityLevel.SAFEST
else -> throw IllegalStateException("Security Level $level is not valid")
}
}
}
......@@ -61,6 +61,7 @@ import org.mozilla.fenix.settings.registerOnSharedPreferenceChangeListener
import org.mozilla.fenix.settings.sitepermissions.AUTOPLAY_BLOCK_ALL
import org.mozilla.fenix.settings.sitepermissions.AUTOPLAY_BLOCK_AUDIBLE
import org.mozilla.fenix.wallpapers.Wallpaper
import org.mozilla.fenix.tor.SecurityLevel
import java.security.InvalidParameterException
import java.util.UUID
......@@ -306,6 +307,33 @@ class Settings(private val appContext: Context) : PreferencesHolder {
false,
)
var standardSecurityLevel by booleanPreference(
appContext.getPreferenceKey(SecurityLevel.STANDARD.preferenceKey),
default = true
)
var saferSecurityLevel by booleanPreference(
appContext.getPreferenceKey(SecurityLevel.SAFER.preferenceKey),
default = false
)
var safestSecurityLevel by booleanPreference(
appContext.getPreferenceKey(SecurityLevel.SAFEST.preferenceKey),
default = false
)
// torSecurityLevel is defined as the first |true| preference,
// beginning at the safest level.
// If multiple preferences are true, then that is a bug and the
// highest |true| security level is chosen.
// Standard is the default level.
fun torSecurityLevel(): SecurityLevel = when {
safestSecurityLevel -> SecurityLevel.SAFEST
saferSecurityLevel -> SecurityLevel.SAFER
standardSecurityLevel -> SecurityLevel.STANDARD
else -> SecurityLevel.STANDARD
}
var spoofEnglish by booleanPreference(
appContext.getPreferenceKey(R.string.pref_key_spoof_english),
default = false
......
......@@ -94,6 +94,9 @@
<action
android:id="@+id/action_global_homeSettingsFragment"
app:destination="@id/homeSettingsFragment" />
<action
android:id="@+id/action_global_torSecurityLevelFragment"
app:destination="@id/torSecurityLevelFragment" />
<action
android:id="@+id/action_global_privateBrowsingFragment"
app:destination="@id/privateBrowsingFragment" />
......@@ -602,6 +605,13 @@
app:exitAnim="@anim/slide_out_left"
app:popEnterAnim="@anim/slide_in_left"
app:popExitAnim="@anim/slide_out_right" />
<action
android:id="@+id/action_settingsFragment_to_torSecurityLevelFragment"
app:destination="@id/torSecurityLevelFragment"
app:enterAnim="@anim/slide_in_right"
app:exitAnim="@anim/slide_out_left"
app:popEnterAnim="@anim/slide_in_left"
app:popExitAnim="@anim/slide_out_right" />
<action
android:id="@+id/action_settingsFragment_to_privateBrowsingFragment"
app:destination="@id/privateBrowsingFragment"
......@@ -847,6 +857,10 @@
android:id="@+id/customizationFragment"
android:name="org.mozilla.fenix.settings.CustomizationFragment"
android:label="@string/preferences_customize" />
<fragment
android:id="@+id/torSecurityLevelFragment"
android:name="org.mozilla.fenix.settings.TorSecurityLevelFragment"
android:label="@string/preferences_tor_security_level_options" />
<fragment
android:id="@+id/privateBrowsingFragment"
android:name="org.mozilla.fenix.settings.PrivateBrowsingFragment"
......
......@@ -430,5 +430,11 @@
<string name="pref_key_noscript_updated" translatable="false">pref_key_noscript_updated</string>
<string name="pref_key_https_everywhere_removed" translatable="false">pref_key_https_everywhere_removed</string>
<!-- Security Level Settings -->
<string name="pref_key_tor_security_level_settings" translatable="false">pref_key_tor_security_level_settings</string>
<string name="pref_key_tor_security_level_standard_option" translatable="false">pref_key_tor_security_level_standard_option</string>
<string name="pref_key_tor_security_level_safer_option" translatable="false">pref_key_tor_security_level_safer_option</string>
<string name="pref_key_tor_security_level_safest_option" translatable="false">pref_key_tor_security_level_safest_option</string>
<string name="pref_key_spoof_english" translatable="false">pref_key_spoof_english</string>
</resources>
......@@ -101,6 +101,11 @@
android:title="@string/preferences_category_privacy_security"
android:layout="@layout/preference_category_no_icon_style">
<androidx.preference.Preference
android:key="@string/pref_key_tor_security_level_settings"
app:iconSpaceReserved="false"
android:title="@string/preferences_tor_security_level_options" />
<androidx.preference.Preference
android:key="@string/pref_key_private_browsing"
app:iconSpaceReserved="false"
......
<?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.preference.PreferenceScreen xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto">
<org.mozilla.fenix.settings.RadioButtonPreference
android:defaultValue="true"
android:key="@string/pref_key_tor_security_level_standard_option"
android:summary="@string/tor_security_level_standard_description"
android:title="@string/tor_security_level_standard_option" />
<org.mozilla.fenix.settings.RadioButtonPreference
android:defaultValue="false"
android:key="@string/pref_key_tor_security_level_safer_option"
android:summary="@string/tor_security_level_safer_description"
android:title="@string/tor_security_level_safer_option" />
<org.mozilla.fenix.settings.RadioButtonPreference
android:defaultValue="false"
android:key="@string/pref_key_tor_security_level_safest_option"
android:summary="@string/tor_security_level_safest_description"
android:title="@string/tor_security_level_safest_option" />
</androidx.preference.PreferenceScreen>
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please to comment