GitLab is used only for code review, issue tracking and project management. Canonical locations for source code are still https://gitweb.torproject.org/ https://git.torproject.org/ and git-rw.torproject.org.

Unverified Commit 81e94daa authored by Matthew Finkel's avatar Matthew Finkel
Browse files

Add Security Level UI

Bug 40026: Implement Security Level settings

Bug 40026: Integrate Security Level settings
parent 16e71cc2
Pipeline #5174 failed with stages
...@@ -111,6 +111,7 @@ class Core( ...@@ -111,6 +111,7 @@ class Core(
context, context,
R.color.foundation_normal_theme R.color.foundation_normal_theme
), ),
torSecurityLevel = context.settings().torSecurityLevel().intRepresentation,
spoofEnglish = context.settings().spoofEnglish spoofEnglish = context.settings().spoofEnglish
) )
......
...@@ -483,6 +483,8 @@ class DefaultSessionControlController( ...@@ -483,6 +483,8 @@ class DefaultSessionControlController(
} }
override fun handleOpenSecurityLevelSettingsClicked() { override fun handleOpenSecurityLevelSettingsClicked() {
val directions = HomeFragmentDirections.actionGlobalTorSecurityLevelFragment()
navController.nav(R.id.homeFragment, directions)
} }
override fun handleWhatsNewGetAnswersClicked() { override fun handleWhatsNewGetAnswersClicked() {
......
...@@ -8,8 +8,11 @@ import android.view.View ...@@ -8,8 +8,11 @@ import android.view.View
import androidx.recyclerview.widget.RecyclerView import androidx.recyclerview.widget.RecyclerView
import kotlinx.android.synthetic.main.tor_onboarding_security_level.view.* import kotlinx.android.synthetic.main.tor_onboarding_security_level.view.*
import org.mozilla.fenix.R import org.mozilla.fenix.R
import org.mozilla.fenix.ext.components
import org.mozilla.fenix.home.sessioncontrol.OnboardingInteractor import org.mozilla.fenix.home.sessioncontrol.OnboardingInteractor
import org.mozilla.fenix.onboarding.OnboardingRadioButton import org.mozilla.fenix.onboarding.OnboardingRadioButton
import org.mozilla.fenix.tor.SecurityLevel
import org.mozilla.fenix.tor.SecurityLevelUtil
import org.mozilla.fenix.utils.view.addToRadioGroup import org.mozilla.fenix.utils.view.addToRadioGroup
class TorOnboardingSecurityLevelViewHolder( class TorOnboardingSecurityLevelViewHolder(
...@@ -33,34 +36,56 @@ class TorOnboardingSecurityLevelViewHolder( ...@@ -33,34 +36,56 @@ class TorOnboardingSecurityLevelViewHolder(
) )
view.open_settings_button.setOnClickListener { view.open_settings_button.setOnClickListener {
interactor.onOpenSettingsClicked() interactor.onOpenSecurityLevelSettingsClicked()
} }
setupRadioGroup() setupRadioGroup(view)
} }
private fun setupRadioGroup() { private fun setupRadioGroup(view: View) {
addToRadioGroup(standardSecurityLevel, saferSecurityLevel, safestSecurityLevel) addToRadioGroup(standardSecurityLevel, saferSecurityLevel, safestSecurityLevel)
standardSecurityLevel.isChecked = true val securityLevel = try {
safestSecurityLevel.isChecked = false SecurityLevelUtil.getSecurityLevelFromInt(
saferSecurityLevel.isChecked = false view.context.components.core.engine.settings.torSecurityLevel
)
} catch (e: IllegalStateException) {
SecurityLevel.STANDARD
}
standardSecurityLevel.isChecked = securityLevel == SecurityLevel.STANDARD
safestSecurityLevel.isChecked = securityLevel == SecurityLevel.SAFEST
saferSecurityLevel.isChecked = securityLevel == SecurityLevel.SAFER
standardSecurityLevel.onClickListener { standardSecurityLevel.onClickListener {
updateSecurityLevel() updateSecurityLevel(SecurityLevel.STANDARD)
} }
saferSecurityLevel.onClickListener { saferSecurityLevel.onClickListener {
updateSecurityLevel() updateSecurityLevel(SecurityLevel.SAFER)
} }
safestSecurityLevel.onClickListener { safestSecurityLevel.onClickListener {
updateSecurityLevel() updateSecurityLevel(SecurityLevel.SAFEST)
} }
updateSecurityLevel(securityLevel)
} }
private fun updateSecurityLevel() { private fun updateSecurityLevel(newLevel: SecurityLevel) {
val resources = itemView.context.resources
val securityLevel = when (newLevel) {
SecurityLevel.STANDARD -> resources.getString(R.string.tor_security_level_standard_option)
SecurityLevel.SAFER -> resources.getString(R.string.tor_security_level_safer_option)
SecurityLevel.SAFEST -> resources.getString(R.string.tor_security_level_safest_option)
}
itemView.current_level.text = resources.getString(
R.string.tor_onboarding_chosen_security_level_label, securityLevel
)
itemView.context.components.let {
it.core.engine.settings.torSecurityLevel = newLevel.intRepresentation
}
} }
companion object { companion object {
......
...@@ -232,6 +232,9 @@ class SettingsFragment : PreferenceFragmentCompat() { ...@@ -232,6 +232,9 @@ class SettingsFragment : PreferenceFragmentCompat() {
resources.getString(R.string.pref_key_tor_network_settings) -> { resources.getString(R.string.pref_key_tor_network_settings) -> {
SettingsFragmentDirections.actionSettingsFragmentToTorNetworkSettingsFragment() SettingsFragmentDirections.actionSettingsFragmentToTorNetworkSettingsFragment()
} }
resources.getString(R.string.pref_key_tor_security_level_settings) -> {
SettingsFragmentDirections.actionSettingsFragmentToTorSecurityLevelFragment()
}
resources.getString(R.string.pref_key_tracking_protection_settings) -> { resources.getString(R.string.pref_key_tracking_protection_settings) -> {
requireContext().metrics.track(Event.TrackingProtectionSettings) requireContext().metrics.track(Event.TrackingProtectionSettings)
SettingsFragmentDirections.actionSettingsFragmentToTrackingProtectionFragment() SettingsFragmentDirections.actionSettingsFragmentToTrackingProtectionFragment()
......
/* 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 onResume() {
super.onResume()
showToolbar(getString(R.string.preferences_tor_security_level_options))
}
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.android.parcel.Parcelize
import org.mozilla.fenix.R
@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 = SecurityLevel.SECURITY_LEVEL_STANDARD
),
SAFER(
preferenceKey = R.string.pref_key_tor_security_level_safer_option,
contentDescriptionRes = R.string.tor_security_level_safer_description,
intRepresentation = SecurityLevel.SECURITY_LEVEL_SAFER
),
SAFEST(
preferenceKey = R.string.pref_key_tor_security_level_safest_option,
contentDescriptionRes = R.string.tor_security_level_safest_description,
intRepresentation = SecurityLevel.SECURITY_LEVEL_SAFEST
);
companion object {
const val SECURITY_LEVEL_STANDARD = 4
const val SECURITY_LEVEL_SAFER = 2
const val SECURITY_LEVEL_SAFEST = 1
}
}
object SecurityLevelUtil {
fun getSecurityLevelFromInt(level: Int): SecurityLevel {
return when (level) {
SecurityLevel.SECURITY_LEVEL_STANDARD -> SecurityLevel.STANDARD
SecurityLevel.SECURITY_LEVEL_SAFER -> SecurityLevel.SAFER
SecurityLevel.SECURITY_LEVEL_SAFEST -> SecurityLevel.SAFEST
else -> throw IllegalStateException("Security Level $level is not valid")
}
}
}
...@@ -40,6 +40,7 @@ import org.mozilla.fenix.settings.deletebrowsingdata.DeleteBrowsingDataOnQuitTyp ...@@ -40,6 +40,7 @@ import org.mozilla.fenix.settings.deletebrowsingdata.DeleteBrowsingDataOnQuitTyp
import org.mozilla.fenix.settings.logins.SavedLoginsSortingStrategyMenu import org.mozilla.fenix.settings.logins.SavedLoginsSortingStrategyMenu
import org.mozilla.fenix.settings.logins.SortingStrategy import org.mozilla.fenix.settings.logins.SortingStrategy
import org.mozilla.fenix.settings.registerOnSharedPreferenceChangeListener import org.mozilla.fenix.settings.registerOnSharedPreferenceChangeListener
import org.mozilla.fenix.tor.SecurityLevel
import java.security.InvalidParameterException import java.security.InvalidParameterException
private const val AUTOPLAY_USER_SETTING = "AUTOPLAY_USER_SETTING" private const val AUTOPLAY_USER_SETTING = "AUTOPLAY_USER_SETTING"
...@@ -168,6 +169,33 @@ class Settings(private val appContext: Context) : PreferencesHolder { ...@@ -168,6 +169,33 @@ class Settings(private val appContext: Context) : PreferencesHolder {
false 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( var spoofEnglish by booleanPreference(
appContext.getPreferenceKey(R.string.pref_key_spoof_english), appContext.getPreferenceKey(R.string.pref_key_spoof_english),
default = false default = false
......
...@@ -32,9 +32,18 @@ ...@@ -32,9 +32,18 @@
android:textAppearance="@style/Body14TextStyle" android:textAppearance="@style/Body14TextStyle"
app:layout_constraintEnd_toEndOf="parent" app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent" app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@id/header_text" app:layout_constraintTop_toBottomOf="@id/current_level"
tools:text="@string/tor_onboarding_security_level_description" /> tools:text="@string/tor_onboarding_security_level_description" />
<TextView
android:id="@+id/current_level"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="12dp"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@id/header_text"
tools:text="@string/tor_onboarding_chosen_security_level_label" />
<org.mozilla.fenix.onboarding.OnboardingRadioButton <org.mozilla.fenix.onboarding.OnboardingRadioButton
android:id="@+id/security_level_standard_option" android:id="@+id/security_level_standard_option"
......
...@@ -60,6 +60,9 @@ ...@@ -60,6 +60,9 @@
<action <action
android:id="@+id/action_global_syncedTabsFragment" android:id="@+id/action_global_syncedTabsFragment"
app:destination="@id/syncedTabsFragment" /> app:destination="@id/syncedTabsFragment" />
<action
android:id="@+id/action_global_torSecurityLevelFragment"
app:destination="@id/torSecurityLevelFragment" />
<action <action
android:id="@+id/action_global_privateBrowsingFragment" android:id="@+id/action_global_privateBrowsingFragment"
app:destination="@id/privateBrowsingFragment" /> app:destination="@id/privateBrowsingFragment" />
...@@ -509,6 +512,13 @@ ...@@ -509,6 +512,13 @@
app:exitAnim="@anim/slide_out_left" app:exitAnim="@anim/slide_out_left"
app:popEnterAnim="@anim/slide_in_left" app:popEnterAnim="@anim/slide_in_left"
app:popExitAnim="@anim/slide_out_right" /> 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 <action
android:id="@+id/action_settingsFragment_to_privateBrowsingFragment" android:id="@+id/action_settingsFragment_to_privateBrowsingFragment"
app:destination="@id/privateBrowsingFragment" app:destination="@id/privateBrowsingFragment"
...@@ -672,6 +682,10 @@ ...@@ -672,6 +682,10 @@
android:id="@+id/customizationFragment" android:id="@+id/customizationFragment"
android:name="org.mozilla.fenix.settings.CustomizationFragment" android:name="org.mozilla.fenix.settings.CustomizationFragment"
android:label="@string/preferences_customize" /> android:label="@string/preferences_customize" />
<fragment
android:id="@+id/torSecurityLevelFragment"
android:name="org.mozilla.fenix.settings.TorSecurityLevelFragment"
android:label="@string/preferences_tor_security_level_settings" />
<fragment <fragment
android:id="@+id/privateBrowsingFragment" android:id="@+id/privateBrowsingFragment"
android:name="org.mozilla.fenix.settings.PrivateBrowsingFragment" android:name="org.mozilla.fenix.settings.PrivateBrowsingFragment"
......
...@@ -23,6 +23,7 @@ ...@@ -23,6 +23,7 @@
<string name="tor_onboarding_security_level">Set your Security Level</string> <string name="tor_onboarding_security_level">Set your Security Level</string>
<string name="tor_onboarding_security_level_description">Disable certain web features that can be used to attack you, and harm your security, anonymity, and privacy.</string> <string name="tor_onboarding_security_level_description">Disable certain web features that can be used to attack you, and harm your security, anonymity, and privacy.</string>
<string name="tor_onboarding_chosen_security_level_label">Current Security Level: %s</string>
<string name="tor_onboarding_security_settings_button">Open Security Settings</string> <string name="tor_onboarding_security_settings_button">Open Security Settings</string>
<string name="tor_onboarding_donate_header">Donate and keep Tor safe</string> <string name="tor_onboarding_donate_header">Donate and keep Tor safe</string>
<string name="tor_onboarding_donate_description">Tor is free to use because of donations from people like you.</string> <string name="tor_onboarding_donate_description">Tor is free to use because of donations from people like you.</string>
...@@ -57,6 +58,10 @@ ...@@ -57,6 +58,10 @@
<string name="preferences_tor_network_settings_restarting">Restarting</string> <string name="preferences_tor_network_settings_restarting">Restarting</string>
<string name="preferences_tor_network_settings_bridges_enabled">Bridges are enabled: %s</string> <string name="preferences_tor_network_settings_bridges_enabled">Bridges are enabled: %s</string>
<!-- Preference title for security level settings -->
<string name="preferences_tor_security_level_settings">Security Settings</string>
<string name="preferences_tor_security_level_options">Security Level</string>
<!-- Description of security levels --> <!-- Description of security levels -->
<string name="tor_security_level_standard_option">Standard</string> <string name="tor_security_level_standard_option">Standard</string>
<string name="tor_security_level_standard_description">All Tor Browser and website features are enabled.</string> <string name="tor_security_level_standard_description">All Tor Browser and website features are enabled.</string>
......
...@@ -90,6 +90,11 @@ ...@@ -90,6 +90,11 @@
app:iconSpaceReserved="false" app:iconSpaceReserved="false"
android:layout="@layout/preference_cat_style"> android:layout="@layout/preference_cat_style">
<androidx.preference.Preference
android:icon="@drawable/ic_tracking_protection_enabled"
android:key="@string/pref_key_tor_security_level_settings"
android:title="@string/preferences_tor_security_level_settings"/>
<androidx.preference.Preference <androidx.preference.Preference
android:icon="@drawable/ic_private_browsing" android:icon="@drawable/ic_private_browsing"
android:key="@string/pref_key_private_browsing" android:key="@string/pref_key_private_browsing"
......
...@@ -87,6 +87,11 @@ ...@@ -87,6 +87,11 @@
android:title="@string/preferences_category_privacy_security" android:title="@string/preferences_category_privacy_security"
android:layout="@layout/preference_category_no_icon_style"> 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_settings"/>
<androidx.preference.Preference <androidx.preference.Preference
android:key="@string/pref_key_private_browsing" android:key="@string/pref_key_private_browsing"
app:iconSpaceReserved="false" 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>
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment