Pier Angelo Vendrame pushed to branch tor-browser-151.0a1-16.0-1 at The Tor Project / Applications / Tor Browser Commits: ac6d26b2 by Leo Tenenbaum at 2026-06-01T10:28:10+02:00 Bug 2040704 - Respect privacy.spoof_english in datetime input validation messages. r=timhuang,dom-core,hsivonen Differential Revision: https://phabricator.services.mozilla.com/D301531 - - - - - 6f6690e1 by Pier Angelo Vendrame at 2026-06-01T10:34:21+02:00 BB 44999: Fix the privacy panel. This commit might be dropped in 153. For 152, it might need adjustments, or we might be able to cherry-pick upstream's commit (Bug 2042309). - - - - - 7 changed files: - browser/components/preferences/config/privacy.mjs - dom/html/input/DateTimeInputTypes.cpp - dom/html/input/DateTimeInputTypes.h - dom/html/test/browser.toml - + dom/html/test/browser_validationmessage_spoof_english.js - intl/locale/AppDateTimeFormat.cpp - intl/locale/AppDateTimeFormat.h Changes: ===================================== browser/components/preferences/config/privacy.mjs ===================================== @@ -742,6 +742,13 @@ Preferences.addAll([ }, { id: "app.normandy.enabled", type: "bool" }, { id: "browser.privacySegmentation.preferences.show", type: "bool" }, + + // Preference instances for prefs that we need to monitor while the page is open. + { id: "app.shield.optoutstudies.enabled", type: "bool" }, + { id: "browser.discovery.enabled", type: "bool" }, + { id: "datareporting.healthreport.uploadEnabled", type: "bool" }, + { id: "datareporting.usage.uploadEnabled", type: "bool" }, + { id: "dom.private-attribution.submission.enabled", type: "bool" }, ]); if (SECURITY_PRIVACY_STATUS_CARD_ENABLED) { @@ -2983,17 +2990,6 @@ Preferences.addSetting({ !ipProtectionSubscribedToVpn.value, }); -// Study opt out -if (lazy.AppConstants.MOZ_DATA_REPORTING) { - Preferences.addAll([ - // Preference instances for prefs that we need to monitor while the page is open. - { id: "app.shield.optoutstudies.enabled", type: "bool" }, - { id: "browser.discovery.enabled", type: "bool" }, - { id: "datareporting.healthreport.uploadEnabled", type: "bool" }, - { id: "datareporting.usage.uploadEnabled", type: "bool" }, - { id: "dom.private-attribution.submission.enabled", type: "bool" }, - ]); -} // Privacy segmentation section Preferences.add({ id: "browser.dataFeatureRecommendations.enabled", ===================================== dom/html/input/DateTimeInputTypes.cpp ===================================== @@ -109,21 +109,19 @@ bool DateTimeInputTypeBase::HasBadInput() const { return !allEmpty && IsValueEmpty(); } -// Format PRExplodedTime according to current locale -static bool FormatDateTime( +bool DateTimeInputTypeBase::FormatDateTime( const PRExplodedTime& aTime, const intl::DateTimeFormat::ComponentsBag& aComponents, - nsAString& aFormatted) { + nsAString& aFormatted) const { // AppDateTimeFormat is not thread-safe. MOZ_ASSERT(NS_IsMainThread(), "Should only be called from main thread"); - return NS_SUCCEEDED( - intl::AppDateTimeFormat::Format(aComponents, &aTime, aFormatted)); + return NS_SUCCEEDED(intl::AppDateTimeFormat::FormatForDocument( + aComponents, &aTime, mInputElement->OwnerDoc(), aFormatted)); } -// Format timestamp according to current locale -static bool FormatDateTime( +bool DateTimeInputTypeBase::FormatDateTime( double aValue, const intl::DateTimeFormat::ComponentsBag& aComponents, - nsAString& aFormatted) { + nsAString& aFormatted) const { PRExplodedTime exploded; PRTime time = static_cast<PRTime>(aValue * PR_USEC_PER_MSEC); PR_ExplodeTime( ===================================== dom/html/input/DateTimeInputTypes.h ===================================== @@ -6,6 +6,9 @@ #define mozilla_dom_DateTimeInputTypes_h_ #include "mozilla/dom/InputType.h" +#include "mozilla/intl/DateTimeFormat.h" + +struct PRExplodedTime; namespace mozilla::dom { @@ -39,6 +42,19 @@ class DateTimeInputTypeBase : public InputType { bool GetTimeFromMs(double aValue, uint16_t* aHours, uint16_t* aMinutes, uint16_t* aSeconds, uint16_t* aMilliseconds) const; + /** + * Format PRExplodedTime according to current locale + */ + bool FormatDateTime(const PRExplodedTime& aTime, + const intl::DateTimeFormat::ComponentsBag& aComponents, + nsAString& aFormatted) const; + /** + * Format timestamp according to current locale + */ + bool FormatDateTime(double aValue, + const intl::DateTimeFormat::ComponentsBag& aComponents, + nsAString& aFormatted) const; + // Minimum year limited by HTML standard, year >= 1. static const double kMinimumYear; // Maximum year limited by ECMAScript date object range, year <= 275760. ===================================== dom/html/test/browser.toml ===================================== @@ -51,3 +51,5 @@ support-files = [ "empty.html", "image_yellow.png", ] + +["browser_validationmessage_spoof_english.js"] ===================================== dom/html/test/browser_validationmessage_spoof_english.js ===================================== @@ -0,0 +1,86 @@ +/* Any copyright is dedicated to the Public Domain. + https://creativecommons.org/publicdomain/zero/1.0/ */ + +"use strict"; + +/* +Test for bug 2040704 - datetime input validation messages should use + en_US localization when English spoofing is enabled. +*/ + +const originalAvailableLocales = Services.locale.availableLocales; +const originalRequestedLocales = Services.locale.requestedLocales; + +async function runTest(test) { + for (let spoof of [false, true]) { + await SpecialPowers.pushPrefEnv({ + set: [ + ["privacy.spoof_english", spoof ? 2 : 0], + ["privacy.resistFingerprinting", spoof], + ], + }); + let source = `<!DOCTYPE html> +<input type="${test.type}" min="${test.min}" value="${test.value}">`; + let result = await BrowserTestUtils.withNewTab( + "data:text/html," + source, + browser => { + return SpecialPowers.spawn(browser, [], () => { + return content.eval( + 'document.querySelector("input").validationMessage' + ); + }); + } + ); + let expectIncludes = test[spoof ? "en" : "de"]; + let expectDoesNotInclude = test[spoof ? "de" : "en"]; + ok( + result.includes(expectIncludes), + `With spoofing ${spoof ? "enabled" : "disabled"}: expect validationMessage ` + + `to include "${expectIncludes}": "${result}"` + ); + ok( + !result.includes(expectDoesNotInclude), + `With spoofing ${spoof ? "enabled" : "disabled"}: expect validationMessage ` + + `to not include "${expectDoesNotInclude}": "${result}"` + ); + } +} + +const tests = [ + { + type: "date", + min: "2000-01-01", + value: "1999-01-01", + en: "01/01/2000", + de: "01.01.2000", + }, + { + type: "time", + min: "16:00", + value: "15:00", + en: "4:00 PM", + de: "16:00", + }, + { + type: "datetime-local", + min: "2000-01-01T00:00", + value: "1999-01-01T00:00", + en: "01/01/2000", + de: "01.01.2000", + }, +]; + +add_task(() => { + Services.locale.availableLocales = ["de-DE"]; + Services.locale.requestedLocales = ["de-DE"]; +}); + +for (let test of tests) { + add_task(() => runTest(test)); +} + +add_task(() => { + // restore previous locales + Services.locale.availableLocales = originalAvailableLocales; + Services.locale.requestedLocales = originalRequestedLocales; +}); ===================================== intl/locale/AppDateTimeFormat.cpp ===================================== @@ -10,6 +10,8 @@ #include "mozilla/intl/LocaleService.h" #include "OSPreferences.h" #include "mozIOSPreferences.h" +#include "nsContentUtils.h" +#include "nsRFPService.h" #ifdef DEBUG # include "nsThreadManager.h" #endif @@ -64,6 +66,14 @@ nsresult AppDateTimeFormat::Format(const DateTimeFormat::StyleBag& aStyle, nsresult AppDateTimeFormat::Format(const DateTimeFormat::ComponentsBag& aBag, const PRExplodedTime* aExplodedTime, nsAString& aStringOut) { + return FormatForDocument(aBag, aExplodedTime, nullptr, aStringOut); +} + +/*static*/ +nsresult AppDateTimeFormat::FormatForDocument( + const DateTimeFormat::ComponentsBag& aBag, + const PRExplodedTime* aExplodedTime, const dom::Document* aForDocument, + nsAString& aStringOut) { // set up locale data nsresult rv = Initialize(); if (NS_FAILED(rv)) { @@ -75,12 +85,17 @@ nsresult AppDateTimeFormat::Format(const DateTimeFormat::ComponentsBag& aBag, nsAutoString timeZoneID; BuildTimeZoneString(aExplodedTime->tm_params, timeZoneID); - auto genResult = DateTimePatternGenerator::TryCreate(sLocale->get()); + const bool spoofEnglish = + aForDocument && nsContentUtils::ShouldResistFingerprinting( + aForDocument, mozilla::RFPTarget::JSLocale); + const nsCString& locale = + spoofEnglish ? nsRFPService::GetSpoofedJSLocale() : *sLocale; + auto genResult = DateTimePatternGenerator::TryCreate(locale.get()); NS_ENSURE_TRUE(genResult.isOk(), NS_ERROR_FAILURE); auto dateTimePatternGenerator = genResult.unwrap(); auto result = DateTimeFormat::TryCreateFromComponents( - *sLocale, aBag, dateTimePatternGenerator.get(), + locale, aBag, dateTimePatternGenerator.get(), Some(Span<const char16_t>(timeZoneID.Data(), timeZoneID.Length()))); NS_ENSURE_TRUE(result.isOk(), NS_ERROR_FAILURE); auto dateTimeFormat = result.unwrap(); ===================================== intl/locale/AppDateTimeFormat.h ===================================== @@ -13,6 +13,10 @@ #include "prtime.h" #include "mozilla/intl/DateTimeFormat.h" +namespace mozilla::dom { +class Document; +} + namespace mozilla::intl { /** @@ -48,6 +52,15 @@ class AppDateTimeFormat { const PRExplodedTime* aExplodedTime, nsAString& aStringOut); + /** + * Format a DateTime for a document, respecting the privacy.spoof_english + * preference. + */ + static nsresult FormatForDocument(const DateTimeFormat::ComponentsBag& aStyle, + const PRExplodedTime* aExplodedTime, + const dom::Document* aForDocument, + nsAString& aStringOut); + /** * If the app locale changes, the cached locale needs to be reset. */ View it on GitLab: https://gitlab.torproject.org/tpo/applications/tor-browser/-/compare/d58de24... -- View it on GitLab: https://gitlab.torproject.org/tpo/applications/tor-browser/-/compare/d58de24... 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