7d9532ed3a3b
fix: Require versioned consent for site icons (v2.14.74)
- time
- 2026-08-31 12:33 UTC · 1 month ago
- machine
- koh2
- parent
- 1009fd2d3ebd
↓ peach-android-7d9532ed.tar.gzatlas at this save
files changed7 files
VERSION+1 −1app/src/main/java/com/peachpasswords/MainActivity.kt+2 −1app/src/main/java/com/peachpasswords/autofill/AutofillEntryPickerActivity.kt+2 −1app/src/main/java/com/peachpasswords/ui/settings/SettingsCardBodies.kt+4 −2app/src/main/java/com/peachpasswords/ui/settings/SettingsViewModel.kt+4 −1app/src/main/java/com/peachpasswords/vault/VaultSettings.kt+14 −0app/src/test/java/com/peachpasswords/vault/VaultSettingsDefaultsTest.kt+21 −0app/src/main/java/com/peachpasswords/MainActivity.kt+2 −1
@@ -41,6 +41,7 @@4141 import com.peachpasswords.updates.UpdateRepository4242 import com.peachpasswords.vault.VaultLockTimer4343 import com.peachpasswords.vault.VaultRepository44+import com.peachpasswords.vault.faviconsAllowed4445 4546 // FragmentActivity (not ComponentActivity) so androidx BiometricPrompt can attach.4647 @AndroidEntryPoint@@ -122,7 +123,7 @@122123 }123124 CompositionLocalProvider(124125 LocalFavicons provides favicons,125- LocalFaviconsEnabled provides settings.faviconsEnabled,126+ LocalFaviconsEnabled provides faviconsAllowed(settings),126127 ) {127128 PeachTheme(128129 accent = accent,app/src/main/java/com/peachpasswords/autofill/AutofillEntryPickerActivity.kt+2 −1
@@ -67,6 +67,7 @@6767 import com.peachpasswords.vault.VaultEntry6868 import com.peachpasswords.vault.isCard6969 import com.peachpasswords.vault.VaultRepository70+import com.peachpasswords.vault.faviconsAllowed7071 import dagger.hilt.android.AndroidEntryPoint7172 import kotlinx.coroutines.delay7273 import kotlinx.coroutines.launch@@ -154,7 +155,7 @@154155 setContent {155156 CompositionLocalProvider(156157 LocalFavicons provides favicons,157- LocalFaviconsEnabled provides settings.faviconsEnabled,158+ LocalFaviconsEnabled provides faviconsAllowed(settings),158159 ) {159160 PeachTheme(accent = accent, textSize = settings.textSize) {160161 val sheetState = rememberModalBottomSheetState(skipPartiallyExpanded = true)app/src/main/java/com/peachpasswords/ui/settings/SettingsCardBodies.kt+4 −2
@@ -78,6 +78,7 @@7878 import androidx.hilt.navigation.compose.hiltViewModel7979 import com.peachpasswords.vault.VaultSettings8080 import com.peachpasswords.vault.VaultSnapshot81+import com.peachpasswords.vault.faviconsAllowed8182 import kotlinx.coroutines.launch8283 import kotlinx.coroutines.delay8384 import java.text.SimpleDateFormat@@ -349,8 +350,9 @@349350 SubLabel("ICONS", fg)350351 RowLine(fg) {351352 Name("Site icons", fg)352- SubtleButton(if (s.faviconsEnabled) "On" else "Off", fg) {353- if (s.faviconsEnabled) vm.setFaviconsEnabled(false) else showFaviconDisclosure = true353+ val siteIconsAllowed = faviconsAllowed(s)354+ SubtleButton(if (siteIconsAllowed) "On" else "Off", fg) {355+ if (siteIconsAllowed) vm.setFaviconsEnabled(false) else showFaviconDisclosure = true354356 }355357 }356358 if (showFaviconDisclosure) {app/src/main/java/com/peachpasswords/ui/settings/SettingsViewModel.kt+4 −1
@@ -286,7 +286,10 @@286286 fun setReduceMotion(on: Boolean) = mutate { it.copy(reduceMotion = on) }287287 fun setTextSize(size: String) = mutate { it.copy(textSize = size) }288288 fun setUiScale(scale: String) = mutate { it.copy(uiScale = scale) }289- fun setFaviconsEnabled(on: Boolean) = mutate { it.copy(faviconsEnabled = on) }289+ fun setFaviconsEnabled(on: Boolean) = mutate {290+ if (on) com.peachpasswords.vault.grantCurrentFaviconConsent(it)291+ else it.copy(faviconsEnabled = false)292+ }290293 fun setBreachMonitoring(on: Boolean) = mutate { it.copy(breachMonitoring = on) }291294 fun setBiometrics(on: Boolean) = mutate { it.copy(biometricsEnabled = on) }292295 fun setPasskeyProviderEnabled(on: Boolean) = mutate { it.copy(passkeyProviderEnabled = on) }app/src/main/java/com/peachpasswords/vault/VaultSettings.kt+14 −0
@@ -14,6 +14,8 @@1414 val uiScale: String = "auto",1515 /** U1 site icons in lists; off (default) keeps the cleaner initials-only look. */1616 val faviconsEnabled: Boolean = false,17+ /** Version of the DuckDuckGo domain-inventory disclosure the user accepted. */18+ val faviconConsentVersion: Int = 0,1719 val biometricsEnabled: Boolean = false,1820 val trashRetentionDays: Int? = null,1921 val sortOrder: String = "url-first",@@ -27,6 +29,18 @@2729 val duressConfigured: Boolean = false,2830 val shortcuts: Map<String, ShortcutBinding> = emptyMap(),2931 val allowScreenshots: Boolean = false,32+)33+34+internal const val CURRENT_FAVICON_CONSENT_VERSION = 135+36+/** Network-backed site icons are enabled only after consent to the current disclosure. */37+fun faviconsAllowed(settings: VaultSettings): Boolean =38+ settings.faviconsEnabled && settings.faviconConsentVersion >= CURRENT_FAVICON_CONSENT_VERSION39+40+/** Record an explicit acceptance of the current third-party favicon disclosure. */41+fun grantCurrentFaviconConsent(settings: VaultSettings): VaultSettings = settings.copy(42+ faviconsEnabled = true,43+ faviconConsentVersion = CURRENT_FAVICON_CONSENT_VERSION,3044 )3145 3246 @Serializableapp/src/test/java/com/peachpasswords/vault/VaultSettingsDefaultsTest.kt+21 −0
@@ -35,4 +35,25 @@3535 val decoded = VaultCodec.decodeSettings(encoded)3636 assertEquals(original, decoded)3737 }38+39+ @Test fun legacy_enabled_favicons_doNotGainConsentByUpgrade() {40+ val legacy = VaultCodec.decodeSettings("{\"faviconsEnabled\":true}")!!41+42+ assertEquals(0, legacy.faviconConsentVersion)43+ assertFalse(faviconsAllowed(legacy))44+ }45+46+ @Test fun currentExplicitConsentAllowsEnabledFavicons() {47+ val consented = grantCurrentFaviconConsent(VaultSettings())48+49+ assertTrue(consented.faviconsEnabled)50+ assertEquals(CURRENT_FAVICON_CONSENT_VERSION, consented.faviconConsentVersion)51+ assertTrue(faviconsAllowed(consented))52+ }53+54+ @Test fun disabledFaviconsStayOffAfterPriorConsent() {55+ val disabled = grantCurrentFaviconConsent(VaultSettings()).copy(faviconsEnabled = false)56+57+ assertFalse(faviconsAllowed(disabled))58+ }3859 }