brizental pushed to branch tor-browser-153.0esr-16.0-1 at The Tor Project / Applications / Tor Browser Commits: d4d29dca by Beatriz Rizental at 2026-07-28T15:50:37+02:00 BB 45085: [android] Confine GooglePlayIntegrityClient to Components.kt Uplifting: https://phabricator.services.mozilla.com/D313912 - - - - - 584d0657 by Beatriz Rizental at 2026-07-28T15:50:37+02:00 fixup! [android] Disable features and functionality Bug 45085: Disable GooglePlayIntegrity - - - - - 51b77601 by Beatriz Rizental at 2026-07-28T15:50:37+02:00 fixup! [android] Disable features and functionality Bug 45134: Return deterministic NIL value for ClientUUID - - - - - 6 changed files: - mobile/android/fenix/app/build.gradle - mobile/android/fenix/app/src/main/java/org/mozilla/fenix/FenixApplication.kt - mobile/android/fenix/app/src/main/java/org/mozilla/fenix/components/ClientUUID.kt - mobile/android/fenix/app/src/main/java/org/mozilla/fenix/components/Components.kt - mobile/android/fenix/app/src/main/java/org/mozilla/fenix/components/llm/Llm.kt - mobile/android/fenix/app/src/test/java/org/mozilla/fenix/components/ClientUUIDTest.kt Changes: ===================================== mobile/android/fenix/app/build.gradle ===================================== @@ -564,7 +564,6 @@ dependencies { implementation project(':components:lib-push-firebase') implementation project(':components:lib-state') implementation project(':components:lib-accelerometer-sensormanager') - implementation project(':components:lib-integrity-googleplay') implementation project(':components:lib-llm-mlpa') implementation project(':components:lib-shake') implementation project(':components:lib-ai-controls') ===================================== mobile/android/fenix/app/src/main/java/org/mozilla/fenix/FenixApplication.kt ===================================== @@ -592,7 +592,7 @@ open class FenixApplication : Application(), Provider, ThemeProvider { } runOnVisualCompleteness(queue) { GlobalScope.launch(IO) { - components.integrityClient.warmUp() + components.warmUpIntegrityClient() } } } ===================================== mobile/android/fenix/app/src/main/java/org/mozilla/fenix/components/ClientUUID.kt ===================================== @@ -6,8 +6,6 @@ package org.mozilla.fenix.components import android.content.Context import android.content.SharedPreferences -import androidx.core.content.edit -import mozilla.components.lib.integrity.googleplay.RequestHashProvider import mozilla.components.lib.llm.mlpa.UserIdProvider import mozilla.components.lib.llm.mlpa.service.UserId import mozilla.components.support.ktx.kotlin.toHexString @@ -39,9 +37,15 @@ fun interface Hasher { /** * Generates and persists a stable per-install UUID, used to identify this client - * consistently across [UserIdProvider] and [RequestHashProvider] consumers. + * consistently across [UserIdProvider] consumers and other callers that need a + * stable per-request hash derived from that UUID. */ -interface ClientUUID : UserIdProvider, RequestHashProvider { +interface ClientUUID : UserIdProvider { + /** + * Generates a hash derived from the client's stable UUID. + */ + fun generateHash(): String + companion object { /** * Convenience initializer that creates a [SharedPreferences] to be used by [ClientUUID]. @@ -62,12 +66,9 @@ internal class PrefsBackedClientUUID( private val generateUUID: () -> String = { UUID.randomUUID().toString() }, private val hasher: Hasher = Hasher.sha256, ) : ClientUUID { + // tor-browser#45134: never expose a unique, trackable per-install identifier. private val uuid: String by lazy { - getPrefs().let { prefs -> - prefs.getString(KEY, null) ?: generateUUID().also { - prefs.edit { putString(KEY, it) } - } - } + NIL_UUID } override fun getUserId() = UserId(uuid) @@ -76,5 +77,6 @@ internal class PrefsBackedClientUUID( companion object { private const val KEY = "uuid" + private const val NIL_UUID = "00000000-0000-0000-0000-000000000000" } } ===================================== mobile/android/fenix/app/src/main/java/org/mozilla/fenix/components/Components.kt ===================================== @@ -19,6 +19,7 @@ import kotlinx.coroutines.MainScope import kotlinx.coroutines.SupervisorJob import mozilla.components.concept.ai.controls.AIFeatureBlock import mozilla.components.concept.ai.controls.AIFeatureRegistry +import mozilla.components.concept.integrity.IntegrityClient import mozilla.components.feature.addons.AddonManager import mozilla.components.feature.addons.amo.AMOAddonsProvider import mozilla.components.feature.addons.migration.DefaultSupportedAddonsChecker @@ -31,7 +32,6 @@ import mozilla.components.lib.ai.controls.dataStore import mozilla.components.lib.ai.controls.default import mozilla.components.lib.crash.store.CrashAction import mozilla.components.lib.crash.store.CrashMiddleware -import mozilla.components.lib.integrity.googleplay.GooglePlayIntegrityClient import mozilla.components.lib.llm.mlpa.MlpaTokenStorage import mozilla.components.lib.publicsuffixlist.PublicSuffixList import mozilla.components.service.fxrelay.eligibility.RelayEligibilityStore @@ -437,14 +437,18 @@ class Components(private val context: Context) { ) } - val integrityClient by lazyMonitored { - GooglePlayIntegrityClient.create( - context = context, - projectNumberToken = BuildConfig.GPS_INTEGRITY_TOKEN, - requestHashProvider = clientUUID, - ) + // tor-browser#45085: Disable Google Play Integrity + val integrityClient: IntegrityClient by lazyMonitored { + IntegrityClient { Result.failure(IllegalStateException("Google Play Integrity is disabled")) } } + /** + * Eagerly initializes the underlying Play Integrity token provider. This is exposed + * separately from [integrityClient] because warm-up is specific to the Google + * Play-backed implementation and isn't part of the [IntegrityClient] concept. + */ + suspend fun warmUpIntegrityClient(): Boolean = false // tor-browser#45085: no-op + val termsOfUsePromptRepository by lazyMonitored { DefaultTermsOfUsePromptRepository(settings) } ===================================== mobile/android/fenix/app/src/main/java/org/mozilla/fenix/components/llm/Llm.kt ===================================== @@ -5,8 +5,7 @@ package org.mozilla.fenix.components.llm import mozilla.components.concept.fetch.Client -import mozilla.components.lib.integrity.googleplay.GooglePlayIntegrityClient -import mozilla.components.lib.integrity.googleplay.IntegrityConsumer +import mozilla.components.concept.integrity.IntegrityClient import mozilla.components.lib.llm.mlpa.MlpaLlmProvider import mozilla.components.lib.llm.mlpa.MlpaTokenProvider import mozilla.components.lib.llm.mlpa.MlpaTokenStorage @@ -25,7 +24,7 @@ class Llm( private val client: Client, private val storage: MlpaTokenStorage, private val fxaTokenProvider: FxaAccessTokenProvider, - private val integrityClient: GooglePlayIntegrityClient, + private val integrityClient: IntegrityClient, private val userIdProvider: UserIdProvider, ) { @@ -36,7 +35,7 @@ class Llm( MlpaTokenProvider.choose( MlpaTokenProvider.fxaTokenProvider(fxaTokenProvider), MlpaTokenProvider.mlpaIntegrityHandshake( - integrityClient = integrityClient.forConsumer(IntegrityConsumer.Summarize), + integrityClient = integrityClient, authenticationService = fenixMlpaService, userIdProvider = userIdProvider, storage = storage, ===================================== mobile/android/fenix/app/src/test/java/org/mozilla/fenix/components/ClientUUIDTest.kt ===================================== @@ -7,9 +7,25 @@ package org.mozilla.fenix.components import mozilla.components.lib.llm.mlpa.service.UserId import mozilla.components.support.test.fakes.android.FakeSharedPreferences import org.junit.Assert.assertEquals +import org.junit.Ignore import org.junit.Test class ClientUUIDTest { + @Test + fun `that the client uuid is always the nil uuid, regardless of generateUUID`() { + val prefs = FakeSharedPreferences() + val nilUuid = UserId("00000000-0000-0000-0000-000000000000") + + val first = PrefsBackedClientUUID({ prefs }, generateUUID = { "my-generated-uuid" }) + assertEquals(nilUuid, first.getUserId()) + // idempotency check + assertEquals(nilUuid, first.getUserId()) + + val second = PrefsBackedClientUUID({ prefs }, generateUUID = { "another-generated-uuid" }) + assertEquals(nilUuid, second.getUserId()) + } + + @Ignore("tor-browser#45134: PrefsBackedClientUUID always returns the nil uuid, see the test above") @Test fun `that a client uuid will only be generated the first time`() { val prefs = FakeSharedPreferences() @@ -25,6 +41,7 @@ class ClientUUIDTest { assertEquals(UserId("my-generated-uuid"), second.getUserId()) } + @Ignore("tor-browser#45134: PrefsBackedClientUUID always returns the nil uuid, so the hash is no longer derived from generateUUID's output") @Test fun `that generateHash uses the provided hasher`() { val prefs = FakeSharedPreferences() View it on GitLab: https://gitlab.torproject.org/tpo/applications/tor-browser/-/compare/5436a4c... -- View it on GitLab: https://gitlab.torproject.org/tpo/applications/tor-browser/-/compare/5436a4c... You're receiving this email because of your account on gitlab.torproject.org. Manage all notifications: https://gitlab.torproject.org/-/profile/notifications | Help: https://gitlab.torproject.org/help