Adds privacy presets for Tor Settings

This commit is contained in:
Vitor Pamplona
2024-09-26 17:20:29 -04:00
parent 64ff33e745
commit dea9d698df
4 changed files with 267 additions and 68 deletions

View File

@@ -20,6 +20,7 @@
*/
package com.vitorpamplona.amethyst.ui.tor
import androidx.compose.runtime.derivedStateOf
import androidx.compose.runtime.mutableStateOf
import androidx.lifecycle.ViewModel
@@ -41,6 +42,27 @@ class TorDialogViewModel : ViewModel() {
val nip05VerificationsViaTor = mutableStateOf(false)
val nip96UploadsViaTor = mutableStateOf(false)
val preset =
derivedStateOf {
whichPreset(
TorSettings(
torType = TorType.INTERNAL,
externalSocksPort = -1,
onionRelaysViaTor = onionRelaysViaTor.value,
dmRelaysViaTor = dmRelaysViaTor.value,
newRelaysViaTor = newRelaysViaTor.value,
trustedRelaysViaTor = trustedRelaysViaTor.value,
urlPreviewsViaTor = urlPreviewsViaTor.value,
profilePicsViaTor = profilePicsViaTor.value,
imagesViaTor = imagesViaTor.value,
videosViaTor = videosViaTor.value,
moneyOperationsViaTor = moneyOperationsViaTor.value,
nip05VerificationsViaTor = nip05VerificationsViaTor.value,
nip96UploadsViaTor = nip96UploadsViaTor.value,
),
)
}
fun reset(torSettings: TorSettings) {
torType.value = torSettings.torType
socksPortStr.value = torSettings.externalSocksPort.toString()
@@ -73,4 +95,28 @@ class TorDialogViewModel : ViewModel() {
nip05VerificationsViaTor = nip05VerificationsViaTor.value,
nip96UploadsViaTor = nip96UploadsViaTor.value,
)
fun setPreset(preset: TorPresetType) {
when (preset) {
TorPresetType.DEFAULT -> resetOnlyFlags(torDefaultPreset)
TorPresetType.ONLY_WHEN_NEEDED -> resetOnlyFlags(torOnlyWhenNeededPreset)
TorPresetType.SMALL_PAYLOADS -> resetOnlyFlags(torSmallPayloadsPreset)
TorPresetType.FULL_PRIVACY -> resetOnlyFlags(torFullyPrivate)
TorPresetType.CUSTOM -> { }
}
}
fun resetOnlyFlags(torSettings: TorSettings) {
onionRelaysViaTor.value = torSettings.onionRelaysViaTor
dmRelaysViaTor.value = torSettings.dmRelaysViaTor
newRelaysViaTor.value = torSettings.newRelaysViaTor
trustedRelaysViaTor.value = torSettings.trustedRelaysViaTor
urlPreviewsViaTor.value = torSettings.urlPreviewsViaTor
profilePicsViaTor.value = torSettings.profilePicsViaTor
imagesViaTor.value = torSettings.imagesViaTor
videosViaTor.value = torSettings.videosViaTor
moneyOperationsViaTor.value = torSettings.moneyOperationsViaTor
nip05VerificationsViaTor.value = torSettings.nip05VerificationsViaTor
nip96UploadsViaTor.value = torSettings.nip96UploadsViaTor
}
}

View File

@@ -56,3 +56,107 @@ fun parseTorType(code: Int?): TorType =
TorType.INTERNAL
}
}
enum class TorPresetType(
val screenCode: Int,
val resourceId: Int,
val explainerId: Int,
) {
ONLY_WHEN_NEEDED(0, R.string.tor_when_needed, R.string.tor_when_needed_explainer),
DEFAULT(1, R.string.tor_default, R.string.tor_default_explainer),
SMALL_PAYLOADS(2, R.string.tor_small_payloads, R.string.tor_small_payloads_explainer),
FULL_PRIVACY(3, R.string.tor_full_privacy, R.string.tor_full_privacy_explainer),
CUSTOM(4, R.string.tor_custom, R.string.tor_custom_explainer),
}
fun parseTorPresetType(code: Int?): TorPresetType =
when (code) {
TorPresetType.ONLY_WHEN_NEEDED.screenCode -> TorPresetType.ONLY_WHEN_NEEDED
TorPresetType.DEFAULT.screenCode -> TorPresetType.DEFAULT
TorPresetType.SMALL_PAYLOADS.screenCode -> TorPresetType.SMALL_PAYLOADS
TorPresetType.FULL_PRIVACY.screenCode -> TorPresetType.FULL_PRIVACY
else -> {
TorPresetType.CUSTOM
}
}
fun isPreset(
torSettings: TorSettings,
preset: TorSettings,
): Boolean =
torSettings.onionRelaysViaTor == preset.onionRelaysViaTor &&
torSettings.dmRelaysViaTor == preset.dmRelaysViaTor &&
torSettings.newRelaysViaTor == preset.newRelaysViaTor &&
torSettings.trustedRelaysViaTor == preset.trustedRelaysViaTor &&
torSettings.urlPreviewsViaTor == preset.urlPreviewsViaTor &&
// torSettings.profilePicsViaTor == preset.profilePicsViaTor &&
torSettings.imagesViaTor == preset.imagesViaTor &&
torSettings.videosViaTor == preset.videosViaTor &&
torSettings.moneyOperationsViaTor == preset.moneyOperationsViaTor &&
torSettings.nip05VerificationsViaTor == preset.nip05VerificationsViaTor &&
torSettings.nip96UploadsViaTor == preset.nip96UploadsViaTor
fun whichPreset(torSettings: TorSettings): TorPresetType {
if (isPreset(torSettings, torOnlyWhenNeededPreset)) return TorPresetType.ONLY_WHEN_NEEDED
if (isPreset(torSettings, torDefaultPreset)) return TorPresetType.DEFAULT
if (isPreset(torSettings, torSmallPayloadsPreset)) return TorPresetType.SMALL_PAYLOADS
if (isPreset(torSettings, torFullyPrivate)) return TorPresetType.FULL_PRIVACY
return TorPresetType.CUSTOM
}
val torOnlyWhenNeededPreset =
TorSettings(
onionRelaysViaTor = true,
dmRelaysViaTor = false,
newRelaysViaTor = false,
trustedRelaysViaTor = false,
urlPreviewsViaTor = false,
profilePicsViaTor = false,
imagesViaTor = false,
videosViaTor = false,
moneyOperationsViaTor = false,
nip05VerificationsViaTor = false,
nip96UploadsViaTor = false,
)
val torDefaultPreset =
TorSettings(
onionRelaysViaTor = true,
dmRelaysViaTor = true,
newRelaysViaTor = true,
trustedRelaysViaTor = false,
urlPreviewsViaTor = false,
profilePicsViaTor = false,
imagesViaTor = false,
videosViaTor = false,
moneyOperationsViaTor = false,
nip05VerificationsViaTor = false,
nip96UploadsViaTor = false,
)
val torSmallPayloadsPreset =
TorSettings(
onionRelaysViaTor = true,
dmRelaysViaTor = true,
newRelaysViaTor = true,
trustedRelaysViaTor = true,
urlPreviewsViaTor = true,
profilePicsViaTor = true,
imagesViaTor = false,
videosViaTor = false,
moneyOperationsViaTor = true,
nip05VerificationsViaTor = true,
nip96UploadsViaTor = false,
)
val torFullyPrivate =
TorSettings(
onionRelaysViaTor = true,
dmRelaysViaTor = true,
newRelaysViaTor = true,
trustedRelaysViaTor = true,
urlPreviewsViaTor = true,
profilePicsViaTor = true,
imagesViaTor = true,
videosViaTor = true,
moneyOperationsViaTor = true,
nip05VerificationsViaTor = true,
nip96UploadsViaTor = true,
)

View File

@@ -53,7 +53,7 @@ import com.vitorpamplona.amethyst.ui.actions.SaveButton
import com.vitorpamplona.amethyst.ui.screen.loggedIn.TitleExplainer
import com.vitorpamplona.amethyst.ui.screen.loggedIn.settings.SettingsRow
import com.vitorpamplona.amethyst.ui.stringRes
import com.vitorpamplona.amethyst.ui.theme.Size15dp
import com.vitorpamplona.amethyst.ui.theme.Size10dp
import com.vitorpamplona.amethyst.ui.theme.ThemeComparisonColumn
import com.vitorpamplona.amethyst.ui.theme.placeholderText
import kotlinx.collections.immutable.persistentListOf
@@ -93,7 +93,7 @@ fun TorDialogContentsPreview() {
onClose = {},
onPost = { },
onError = {},
torSettings = TorSettings(),
torSettings = TorSettings(torType = TorType.EXTERNAL),
)
}
}
@@ -104,6 +104,22 @@ fun TorDialogContents(
onClose: () -> Unit,
onPost: (torSettings: TorSettings) -> Unit,
onError: (String) -> Unit,
) {
val dialogViewModel = viewModel<TorDialogViewModel>()
LaunchedEffect(dialogViewModel, torSettings) {
dialogViewModel.reset(torSettings)
}
TorDialogContents(dialogViewModel, onClose, onPost, onError)
}
@Composable
fun TorDialogContents(
dialogViewModel: TorDialogViewModel,
onClose: () -> Unit,
onPost: (torSettings: TorSettings) -> Unit,
onError: (String) -> Unit,
) {
Column(
modifier =
@@ -113,12 +129,6 @@ fun TorDialogContents(
rememberScrollState(),
).padding(10.dp),
) {
val dialogViewModel = viewModel<TorDialogViewModel>()
LaunchedEffect(dialogViewModel, torSettings) {
dialogViewModel.reset(torSettings)
}
Row(
horizontalArrangement = Arrangement.SpaceBetween,
verticalAlignment = Alignment.CenterVertically,
@@ -142,8 +152,8 @@ fun TorDialogContents(
}
Column(
modifier = Modifier.padding(vertical = 10.dp, horizontal = 5.dp),
verticalArrangement = Arrangement.spacedBy(Size15dp),
modifier = Modifier.padding(horizontal = 5.dp),
verticalArrangement = Arrangement.spacedBy(Size10dp),
) {
SettingsRow(
R.string.use_internal_tor,
@@ -182,75 +192,99 @@ fun TorDialogContents(
)
}
}
}
SwitchSettingsRow(
R.string.tor_use_onion_address,
R.string.tor_use_onion_address_explainer,
dialogViewModel.onionRelaysViaTor,
)
AnimatedVisibility(
visible = dialogViewModel.torType.value != TorType.OFF,
) {
Column(
modifier = Modifier.padding(horizontal = 5.dp),
verticalArrangement = Arrangement.spacedBy(Size10dp),
) {
SettingsRow(
R.string.tor_preset,
R.string.tor_preset_explainer,
persistentListOf(
TitleExplainer(stringRes(TorPresetType.ONLY_WHEN_NEEDED.resourceId), stringRes(TorPresetType.ONLY_WHEN_NEEDED.explainerId)),
TitleExplainer(stringRes(TorPresetType.DEFAULT.resourceId), stringRes(TorPresetType.DEFAULT.explainerId)),
TitleExplainer(stringRes(TorPresetType.SMALL_PAYLOADS.resourceId), stringRes(TorPresetType.SMALL_PAYLOADS.explainerId)),
TitleExplainer(stringRes(TorPresetType.FULL_PRIVACY.resourceId), stringRes(TorPresetType.FULL_PRIVACY.explainerId)),
TitleExplainer(stringRes(TorPresetType.CUSTOM.resourceId), stringRes(TorPresetType.CUSTOM.explainerId)),
),
dialogViewModel.preset.value.screenCode,
) {
dialogViewModel.setPreset(parseTorPresetType(it))
}
SwitchSettingsRow(
R.string.tor_use_dm_relays,
R.string.tor_use_dm_relays_explainer,
dialogViewModel.dmRelaysViaTor,
)
SwitchSettingsRow(
R.string.tor_use_onion_address,
R.string.tor_use_onion_address_explainer,
dialogViewModel.onionRelaysViaTor,
)
SwitchSettingsRow(
R.string.tor_use_new_relays,
R.string.tor_use_new_relays_explainer,
dialogViewModel.newRelaysViaTor,
)
SwitchSettingsRow(
R.string.tor_use_dm_relays,
R.string.tor_use_dm_relays_explainer,
dialogViewModel.dmRelaysViaTor,
)
SwitchSettingsRow(
R.string.tor_use_trusted_relays,
R.string.tor_use_trusted_relays_explainer,
dialogViewModel.trustedRelaysViaTor,
)
SwitchSettingsRow(
R.string.tor_use_new_relays,
R.string.tor_use_new_relays_explainer,
dialogViewModel.newRelaysViaTor,
)
SwitchSettingsRow(
R.string.tor_use_money_operations,
R.string.tor_use_money_operations_explainer,
dialogViewModel.moneyOperationsViaTor,
)
SwitchSettingsRow(
R.string.tor_use_trusted_relays,
R.string.tor_use_trusted_relays_explainer,
dialogViewModel.trustedRelaysViaTor,
)
/**
* Too hard to separate Coil into regular images and profile pics
SwitchSettingsRow(
R.string.tor_use_profile_pictures,
R.string.tor_use_profile_pictures_explainer,
dialogViewModel.profilePicsViaTor,
)
*/
SwitchSettingsRow(
R.string.tor_use_money_operations,
R.string.tor_use_money_operations_explainer,
dialogViewModel.moneyOperationsViaTor,
)
SwitchSettingsRow(
R.string.tor_use_nip05_verification,
R.string.tor_use_nip05_verification_explainer,
dialogViewModel.nip05VerificationsViaTor,
)
/**
* Too hard to separate Coil into regular images and profile pics
SwitchSettingsRow(
R.string.tor_use_profile_pictures,
R.string.tor_use_profile_pictures_explainer,
dialogViewModel.profilePicsViaTor,
)
*/
SwitchSettingsRow(
R.string.tor_use_url_previews,
R.string.tor_use_url_previews_explainer,
dialogViewModel.urlPreviewsViaTor,
)
SwitchSettingsRow(
R.string.tor_use_nip05_verification,
R.string.tor_use_nip05_verification_explainer,
dialogViewModel.nip05VerificationsViaTor,
)
SwitchSettingsRow(
R.string.tor_use_images,
R.string.tor_use_images_explainer,
dialogViewModel.imagesViaTor,
)
SwitchSettingsRow(
R.string.tor_use_url_previews,
R.string.tor_use_url_previews_explainer,
dialogViewModel.urlPreviewsViaTor,
)
SwitchSettingsRow(
R.string.tor_use_videos,
R.string.tor_use_videos_explainer,
dialogViewModel.videosViaTor,
)
SwitchSettingsRow(
R.string.tor_use_images,
R.string.tor_use_images_explainer,
dialogViewModel.imagesViaTor,
)
SwitchSettingsRow(
R.string.tor_use_nip96_uploads,
R.string.tor_use_nip96_uploads_explainer,
dialogViewModel.nip96UploadsViaTor,
)
SwitchSettingsRow(
R.string.tor_use_videos,
R.string.tor_use_videos_explainer,
dialogViewModel.videosViaTor,
)
SwitchSettingsRow(
R.string.tor_use_nip96_uploads,
R.string.tor_use_nip96_uploads_explainer,
dialogViewModel.nip96UploadsViaTor,
)
}
}
}
}

View File

@@ -433,6 +433,9 @@
<string name="use_internal_tor">Active Tor Engine</string>
<string name="use_internal_tor_explainer">Use the internal version or Orbot</string>
<string name="tor_preset">Tor/Privacy Presets</string>
<string name="tor_preset_explainer">Quickly modify all settings below</string>
<string name="tor_use_onion_address">Onion Url/Relays</string>
<string name="tor_use_onion_address_explainer">Use Tor for any .onion url</string>
@@ -470,6 +473,18 @@
<string name="tor_external">Orbot</string>
<string name="tor_off">Off</string>
<string name="tor_when_needed">Basic</string>
<string name="tor_default">Default</string>
<string name="tor_small_payloads">All but Media</string>
<string name="tor_full_privacy">Full Privacy</string>
<string name="tor_custom">Custom</string>
<string name="tor_when_needed_explainer">Use Tor when it\'s required by the server</string>
<string name="tor_default_explainer">Hide your IP from random relays</string>
<string name="tor_small_payloads_explainer">Hide your IP from everything, but images and videos</string>
<string name="tor_full_privacy_explainer">Hide your IP in all connections</string>
<string name="tor_custom_explainer">Make your own</string>
<string name="invalid_port_number">Invalid port number</string>
<string name="use_orbot">Use Orbot</string>
<string name="disconnect_from_your_orbot_setup">Disconnect Tor/Orbot</string>