240e63941c1e

fix: disclose third-party favicon requests before enabling site icons (audit PB-26-020) (v2.14.71)

time
2026-08-30 23:57 UTC · 1 month ago
machine
koh2
agent
GPT-5
session
PEACH_ANDROID_INDEPENDENT_AUDIT_2026-08-30
parent
266eb1358cb7
3 files VERSION+1 −1app/src/main/java/com/peachpasswords/ui/settings/SettingsCardBodies.kt+24 −1app/src/test/java/com/peachpasswords/ui/settings/FaviconDisclosureTest.kt+13 −0
VERSION+1 −1
@@ -1 +1 @@1-2.14.701+2.14.71

view file

app/src/main/java/com/peachpasswords/ui/settings/SettingsCardBodies.kt+24 −1
@@ -26,6 +26,7 @@2626 import androidx.compose.foundation.text.BasicTextField2727 import androidx.compose.runtime.Composable2828 import androidx.compose.material3.CircularProgressIndicator29+import androidx.compose.material3.AlertDialog2930 import androidx.compose.runtime.DisposableEffect3031 import androidx.compose.runtime.collectAsState3132 import androidx.compose.runtime.getValue@@ -85,6 +86,9 @@8586 8687 private const val PRO_URL = "https://buy.polar.sh/polar_cl_IXSFIPojx67rcOTksn8LkH5mnU3osPHtYqBIl1eyuIz"8788 89+internal const val FAVICON_DISCLOSURE_TEXT =90+    "Peach requests site icons from DuckDuckGo. Turning this on discloses your full vault domain inventory to DuckDuckGo as icons are requested."91+8892 /**8993  * Body content for the active stack card. Everything is tinted with the card's9094  * own foreground [fg] (the browser's `currentColor` convention), so each card's@@ -308,6 +312,7 @@308312 @OptIn(ExperimentalLayoutApi::class)309313 @Composable310314 private fun AppearanceBody(fg: Color, vm: SettingsViewModel, s: VaultSettings) {315+    var showFaviconDisclosure by remember { mutableStateOf(false) }311316     SubLabel("ACCENT", fg, top = 0.dp)312317     FlowRow(horizontalArrangement = Arrangement.spacedBy(8.dp), verticalArrangement = Arrangement.spacedBy(8.dp)) {313318         ACCENT_COLORS.forEach { (name, color) ->@@ -344,7 +349,25 @@344349     SubLabel("ICONS", fg)345350     RowLine(fg) {346351         Name("Site icons", fg)347-        SubtleButton(if (s.faviconsEnabled) "On" else "Off", fg) { vm.setFaviconsEnabled(!s.faviconsEnabled) }352+        SubtleButton(if (s.faviconsEnabled) "On" else "Off", fg) {353+            if (s.faviconsEnabled) vm.setFaviconsEnabled(false) else showFaviconDisclosure = true354+        }355+    }356+    if (showFaviconDisclosure) {357+        AlertDialog(358+            onDismissRequest = { showFaviconDisclosure = false },359+            title = { Text("Enable site icons?", color = fg, fontFamily = PeachType.Body) },360+            text = { Text(FAVICON_DISCLOSURE_TEXT, color = fg, fontFamily = PeachType.Body) },361+            confirmButton = {362+                SubtleButton("Enable", fg) {363+                    showFaviconDisclosure = false364+                    vm.setFaviconsEnabled(true)365+                }366+            },367+            dismissButton = {368+                SubtleButton("Cancel", fg) { showFaviconDisclosure = false }369+            },370+        )348371     }349372     SubLabel("MOTION", fg)350373     RowLine(fg) {

view file

app/src/test/java/com/peachpasswords/ui/settings/FaviconDisclosureTest.kt+13 −0
@@ -0,0 +1,13 @@1+package com.peachpasswords.ui.settings2+3+import org.junit.Assert.assertTrue4+import org.junit.Test5+6+class FaviconDisclosureTest {7+    @Test8+    fun site_icon_consent_names_recipient_and_inventory_scope() {9+        assertTrue(FAVICON_DISCLOSURE_TEXT.contains("DuckDuckGo"))10+        assertTrue(FAVICON_DISCLOSURE_TEXT.contains("full vault domain inventory"))11+        assertTrue(FAVICON_DISCLOSURE_TEXT.contains("Turning this on"))12+    }13+}

view file