commit 7120a56c193fc1f74bf6c51bf0956f1d5914181d
parent ddb756b26d890966efc914c409fb402d862e762c
Author: Pier Angelo Vendrame <pierov@torproject.org>
Date: Wed, 8 May 2024 11:35:33 +0200
BB 42562: Normalized the Accepted Languages on Android.
The OS language might be outside the list of actually supported
languages and it might leak the user's region.
Therefore, we force the locale reported in Accept-Language to match one
we support with translations, even when it means using a not exact
region tag.
Diffstat:
2 files changed, 44 insertions(+), 15 deletions(-)
diff --git a/mobile/android/fenix/app/src/main/java/org/mozilla/fenix/gecko/GeckoProvider.kt b/mobile/android/fenix/app/src/main/java/org/mozilla/fenix/gecko/GeckoProvider.kt
@@ -17,6 +17,7 @@ import mozilla.components.lib.crash.handler.CrashHandlerService
import mozilla.components.lib.crash.store.CrashAction
import mozilla.components.service.sync.autofill.GeckoCreditCardsAddressesStorageDelegate
import mozilla.components.service.sync.logins.GeckoLoginStorageDelegate
+import org.mozilla.fenix.BuildConfig
import org.mozilla.fenix.Config
import org.mozilla.fenix.components.appstate.AppAction
import org.mozilla.fenix.ext.components
@@ -127,6 +128,7 @@ object GeckoProvider {
)
.isolatedProcessEnabled(context.settings().isIsolatedProcessEnabled)
.appZygoteProcessEnabled(context.settings().isAppZygoteEnabled)
+ .supportedLocales(BuildConfig.SUPPORTED_LOCALE_ARRAY.toList())
if (FxNimbus.features.fission.value().shouldUseNimbus) {
builder
diff --git a/mobile/android/geckoview/src/main/java/org/mozilla/geckoview/GeckoRuntimeSettings.java b/mobile/android/geckoview/src/main/java/org/mozilla/geckoview/GeckoRuntimeSettings.java
@@ -24,6 +24,8 @@ import java.lang.annotation.RetentionPolicy;
import java.util.Arrays;
import java.util.LinkedHashMap;
import java.util.List;
+import java.util.Collection;
+import java.util.HashMap;
import java.util.Locale;
import org.mozilla.gecko.EventDispatcher;
import org.mozilla.gecko.GeckoSystemStateListener;
@@ -654,6 +656,17 @@ public final class GeckoRuntimeSettings extends RuntimeSettings {
return this;
}
+ public @NonNull Builder supportedLocales(final Collection<String> locales) {
+ getSettings().mSupportedLocales.clear();
+ for (String tag : locales) {
+ Locale locale = Locale.forLanguageTag(tag);
+ getSettings().mSupportedLocales.put(locale, locale);
+ Locale lang = new Locale.Builder().setLanguage(locale.getLanguage()).build();
+ getSettings().mSupportedLocales.put(lang, locale);
+ }
+ return this;
+ }
+
/**
* Set this flag to disable low-memory detection. Set this when running tests to avoid
* unpredictable behavior at runtime.
@@ -884,6 +897,7 @@ public final class GeckoRuntimeSettings extends RuntimeSettings {
/* package */ Class<? extends Service> mCrashHandler;
/* package */ String[] mRequestedLocales;
/* package */ ExperimentDelegate mExperimentDelegate;
+ /* package */ HashMap<Locale, Locale> mSupportedLocales = new HashMap<>();
/**
* Attach and commit the settings to the given runtime.
@@ -938,6 +952,7 @@ public final class GeckoRuntimeSettings extends RuntimeSettings {
mRequestedLocales = settings.mRequestedLocales;
mConfigFilePath = settings.mConfigFilePath;
mExperimentDelegate = settings.mExperimentDelegate;
+ mSupportedLocales = settings.mSupportedLocales;
}
/* package */ void commit() {
@@ -1535,27 +1550,39 @@ public final class GeckoRuntimeSettings extends RuntimeSettings {
EventDispatcher.getInstance().dispatch("GeckoView:SetLocale", data);
}
- private String computeAcceptLanguages() {
- final LinkedHashMap<String, String> locales = new LinkedHashMap<>();
+ private Locale getLocaleIfSupported(String tag) {
+ Locale exact = Locale.forLanguageTag(tag);
+ if (mSupportedLocales.containsKey(exact)) {
+ return exact;
+ }
+ Locale fallback = new Locale.Builder().setLanguage(exact.getLanguage()).build();
+ return mSupportedLocales.get(fallback);
+ }
- // Explicitly-set app prefs come first:
+ private String computeAcceptLanguages() {
+ Locale locale = null;
if (mRequestedLocales != null) {
- for (final String locale : mRequestedLocales) {
- // Requested locales should be in language or language-region format
- final String normalizedLocale =
- LocaleUtils.getLanguageRegionLocale(Locale.forLanguageTag(locale));
- locales.put(normalizedLocale.toLowerCase(Locale.ROOT), normalizedLocale);
+ for (String tag : mRequestedLocales) {
+ locale = getLocaleIfSupported(tag);
+ if (locale != null) {
+ break;
+ }
}
}
- // OS prefs come second:
- for (final String locale : getSystemLocalesForAcceptLanguage()) {
- final String localeLowerCase = locale.toLowerCase(Locale.ROOT);
- if (!locales.containsKey(localeLowerCase)) {
- locales.put(localeLowerCase, locale);
+ if (locale == null) {
+ for (final String tag : getSystemLocalesForAcceptLanguage()) {
+ locale = getLocaleIfSupported(tag);
+ if (locale != null) {
+ break;
+ }
}
}
-
- return TextUtils.join(",", locales.values());
+ String acceptLanguages = locale != null ? locale.toLanguageTag().replace('_', '-') : "en-US";
+ if (acceptLanguages.equals("en-US")) {
+ // For consistency with spoof English.
+ acceptLanguages += ", en";
+ }
+ return acceptLanguages;
}
private static String[] getSystemLocalesForAcceptLanguage() {