Loading browser/base/content/test/general/mochitest.ini +1 −0 Original line number Diff line number Diff line Loading @@ -28,6 +28,7 @@ support-files = [test_bug364677.html] [test_bug395533.html] [test_bug_jsdefaultlocale.html] [test_contextmenu.html] skip-if = toolkit == "gtk2" || toolkit == "gtk3" || (os == 'mac' && os_version != '10.6') # disabled on Linux due to bug 513558, on Mac after 10.6 due to bug 792304 [test_contextmenu_input.html] Loading browser/base/content/test/general/test_bug_jsdefaultlocale.html 0 → 100644 +41 −0 Original line number Diff line number Diff line <!DOCTYPE HTML> <html> <!-- https://bugs.torproject.org/13019 --> <head> <meta charset="utf-8"> <title>Test for Tor Bug #13019: Prevent fingerprinting of JS-exposed locale</title> <script type="application/javascript" src="/tests/SimpleTest/SimpleTest.js"></script> <script type="application/javascript" src="/tests/SimpleTest/EventUtils.js"></script> <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/> </head> <body> <a target="_blank" href="https://bugs.torproject.org">Bug 13019</a> <p id="display"></p> <pre id="test"></pre> <script type="application/javascript;version=1.8"> let prefName = "javascript.use_us_english_locale", originalPrefValue = null, date = new Date(); // Read the current pref value. try { originalPrefValue = SpecialPowers.getBoolPref(prefName); } catch (e) { } // Enable pref "javascript.use_us_english_locale". SpecialPowers.setBoolPref(prefName, true); // Test that we are getting en-US locale everywhere it is exposed in JavaScript is(Intl.Collator().resolvedOptions().locale, "en-US", "content JS locale from Intl.Collator"); is(Intl.DateTimeFormat().resolvedOptions().locale, "en-US", "content JS locale Intl.DateTimeFormat"); is(Intl.NumberFormat().resolvedOptions().locale, "en-US", "content JS locale from Intl.NumberFormat"); is(date.toLocaleString(), date.toLocaleString("en-US"), "Date formatted by JS locale"); // Return pref to its original value, if it had one. if (originalPrefValue === null) { SpecialPowers.clearUserPref(prefName); } else { SpecialPowers.setBoolPref(prefName, originalPrefValue); } </script> </body> </html> js/src/jsapi.cpp +7 −0 Original line number Diff line number Diff line Loading @@ -5217,6 +5217,13 @@ JS_SetDefaultLocale(JSRuntime* rt, const char* locale) return rt->setDefaultLocale(locale); } JS_PUBLIC_API(const char*) JS_GetDefaultLocale(JSRuntime *rt) { AssertHeapIsIdle(rt); return rt->getDefaultLocale(); } JS_PUBLIC_API(void) JS_ResetDefaultLocale(JSRuntime* rt) { Loading js/src/jsapi.h +9 −0 Original line number Diff line number Diff line Loading @@ -4265,6 +4265,15 @@ JS_ParseJSONWithReviver(JSContext* cx, JS::HandleString str, JS::HandleValue rev extern JS_PUBLIC_API(bool) JS_SetDefaultLocale(JSRuntime* rt, const char* locale); /* * Returns the default locale for the ECMAScript Internationalization API * (Intl.Collator, Intl.NumberFormat, Intl.DateTimeFormat). * Note that the Internationalization API encourages clients to * specify their own locales. */ extern JS_PUBLIC_API(const char*) JS_GetDefaultLocale(JSRuntime *rt); /* * Reset the default locale to OS defaults. */ Loading xpcom/build/XPCOMInit.cpp +68 −0 Original line number Diff line number Diff line Loading @@ -8,6 +8,7 @@ #include "mozilla/Atomics.h" #include "mozilla/Poison.h" #include "mozilla/Preferences.h" #include "mozilla/XPCOM.h" #include "nsXULAppAPI.h" Loading Loading @@ -43,6 +44,8 @@ #include "nsSupportsPrimitives.h" #include "nsConsoleService.h" #include "nsIJSRuntimeService.h" #include "nsComponentManager.h" #include "nsCategoryManagerUtils.h" #include "nsIServiceManager.h" Loading Loading @@ -485,6 +488,67 @@ NS_IMPL_ISUPPORTS(NesteggReporter, nsIMemoryReporter) CountingAllocatorBase<NesteggReporter>::sAmount(0); #endif /* MOZ_WEBM */ // Anonymous namespace for customizing the default locale that JavaScript // uses, according to the value of the "javascript.use_us_english_locale" pref. // The current default locale can be detected in JavaScript by calling // `Intl.DateTimeFormat().resolvedOptions().locale` namespace { #define USE_US_ENGLISH_LOCALE_PREF "javascript.use_us_english_locale" static char* sSystemLocale; static char* sJSLocale; // Returns a pointer to the current JS Runtime. static JSRuntime* GetRuntime() { nsresult rv; nsCOMPtr<nsIJSRuntimeService> rts = do_GetService("@mozilla.org/js/xpc/RuntimeService;1", &rv); if (NS_FAILED(rv)) return NULL; JSRuntime* rt; rts->GetRuntime(&rt); return rt; } // If the USE_US_ENGLISH_LOCALE_PREF is active, set all locales to US English. // Otherwise, fall back to the default system and JS locales. static void UseUSEnglishLocalePrefChangedCallback(const char* /* pref */, void* /* closure */) { // Get a pointer to the default JS Runtime. JSRuntime* rt = GetRuntime(); if (rt) { // Read the pref to see if we will use US English locale. bool useUSEnglishLocale = mozilla::Preferences::GetBool(USE_US_ENGLISH_LOCALE_PREF, false); // Set the application-wide C-locale. Needed for Date.toLocaleFormat(). setlocale(LC_ALL, useUSEnglishLocale ? "C" : sSystemLocale); // Now override the JavaScript Runtime Locale that is used by the Intl API // as well as Date.toLocaleString, Number.toLocaleString, and String.localeCompare. JS_SetDefaultLocale(rt, useUSEnglishLocale ? "en-US" : sJSLocale); } } static void StartWatchingUseUSEnglishLocalePref() { // Get the default system locale. To be used if US English locale pref is deactivated. sSystemLocale = strdup(setlocale(LC_ALL,NULL)); // Store the default JavaScript locale. JSRuntime* rt = GetRuntime(); if (rt) { sJSLocale = strdup(JS_GetDefaultLocale(rt)); } // Now keep the locale updated with the current pref value. mozilla::Preferences::RegisterCallbackAndCall(UseUSEnglishLocalePrefChangedCallback, USE_US_ENGLISH_LOCALE_PREF); } static void StopWatchingUseUSEnglishLocalePref() { mozilla::Preferences::UnregisterCallback(UseUSEnglishLocalePrefChangedCallback, USE_US_ENGLISH_LOCALE_PREF); if (sSystemLocale) free(sSystemLocale); if (sJSLocale) JS_free(nullptr, sJSLocale); } } // anonymous namespace for locale hiding // Note that on OSX, aBinDirectory will point to .app/Contents/Resources/browser EXPORT_XPCOM_API(nsresult) NS_InitXPCOM2(nsIServiceManager** aResult, Loading Loading @@ -766,6 +830,8 @@ NS_InitXPCOM2(nsIServiceManager** aResult, mozilla::eventtracer::Init(); #endif // Start watching the "javascript.use_us_english_locale" pref. StartWatchingUseUSEnglishLocalePref(); return NS_OK; } Loading Loading @@ -1038,6 +1104,8 @@ ShutdownXPCOM(nsIServiceManager* aServMgr) delete sExitManager; sExitManager = nullptr; StopWatchingUseUSEnglishLocalePref(); Omnijar::CleanUp(); HangMonitor::Shutdown(); Loading Loading
browser/base/content/test/general/mochitest.ini +1 −0 Original line number Diff line number Diff line Loading @@ -28,6 +28,7 @@ support-files = [test_bug364677.html] [test_bug395533.html] [test_bug_jsdefaultlocale.html] [test_contextmenu.html] skip-if = toolkit == "gtk2" || toolkit == "gtk3" || (os == 'mac' && os_version != '10.6') # disabled on Linux due to bug 513558, on Mac after 10.6 due to bug 792304 [test_contextmenu_input.html] Loading
browser/base/content/test/general/test_bug_jsdefaultlocale.html 0 → 100644 +41 −0 Original line number Diff line number Diff line <!DOCTYPE HTML> <html> <!-- https://bugs.torproject.org/13019 --> <head> <meta charset="utf-8"> <title>Test for Tor Bug #13019: Prevent fingerprinting of JS-exposed locale</title> <script type="application/javascript" src="/tests/SimpleTest/SimpleTest.js"></script> <script type="application/javascript" src="/tests/SimpleTest/EventUtils.js"></script> <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/> </head> <body> <a target="_blank" href="https://bugs.torproject.org">Bug 13019</a> <p id="display"></p> <pre id="test"></pre> <script type="application/javascript;version=1.8"> let prefName = "javascript.use_us_english_locale", originalPrefValue = null, date = new Date(); // Read the current pref value. try { originalPrefValue = SpecialPowers.getBoolPref(prefName); } catch (e) { } // Enable pref "javascript.use_us_english_locale". SpecialPowers.setBoolPref(prefName, true); // Test that we are getting en-US locale everywhere it is exposed in JavaScript is(Intl.Collator().resolvedOptions().locale, "en-US", "content JS locale from Intl.Collator"); is(Intl.DateTimeFormat().resolvedOptions().locale, "en-US", "content JS locale Intl.DateTimeFormat"); is(Intl.NumberFormat().resolvedOptions().locale, "en-US", "content JS locale from Intl.NumberFormat"); is(date.toLocaleString(), date.toLocaleString("en-US"), "Date formatted by JS locale"); // Return pref to its original value, if it had one. if (originalPrefValue === null) { SpecialPowers.clearUserPref(prefName); } else { SpecialPowers.setBoolPref(prefName, originalPrefValue); } </script> </body> </html>
js/src/jsapi.cpp +7 −0 Original line number Diff line number Diff line Loading @@ -5217,6 +5217,13 @@ JS_SetDefaultLocale(JSRuntime* rt, const char* locale) return rt->setDefaultLocale(locale); } JS_PUBLIC_API(const char*) JS_GetDefaultLocale(JSRuntime *rt) { AssertHeapIsIdle(rt); return rt->getDefaultLocale(); } JS_PUBLIC_API(void) JS_ResetDefaultLocale(JSRuntime* rt) { Loading
js/src/jsapi.h +9 −0 Original line number Diff line number Diff line Loading @@ -4265,6 +4265,15 @@ JS_ParseJSONWithReviver(JSContext* cx, JS::HandleString str, JS::HandleValue rev extern JS_PUBLIC_API(bool) JS_SetDefaultLocale(JSRuntime* rt, const char* locale); /* * Returns the default locale for the ECMAScript Internationalization API * (Intl.Collator, Intl.NumberFormat, Intl.DateTimeFormat). * Note that the Internationalization API encourages clients to * specify their own locales. */ extern JS_PUBLIC_API(const char*) JS_GetDefaultLocale(JSRuntime *rt); /* * Reset the default locale to OS defaults. */ Loading
xpcom/build/XPCOMInit.cpp +68 −0 Original line number Diff line number Diff line Loading @@ -8,6 +8,7 @@ #include "mozilla/Atomics.h" #include "mozilla/Poison.h" #include "mozilla/Preferences.h" #include "mozilla/XPCOM.h" #include "nsXULAppAPI.h" Loading Loading @@ -43,6 +44,8 @@ #include "nsSupportsPrimitives.h" #include "nsConsoleService.h" #include "nsIJSRuntimeService.h" #include "nsComponentManager.h" #include "nsCategoryManagerUtils.h" #include "nsIServiceManager.h" Loading Loading @@ -485,6 +488,67 @@ NS_IMPL_ISUPPORTS(NesteggReporter, nsIMemoryReporter) CountingAllocatorBase<NesteggReporter>::sAmount(0); #endif /* MOZ_WEBM */ // Anonymous namespace for customizing the default locale that JavaScript // uses, according to the value of the "javascript.use_us_english_locale" pref. // The current default locale can be detected in JavaScript by calling // `Intl.DateTimeFormat().resolvedOptions().locale` namespace { #define USE_US_ENGLISH_LOCALE_PREF "javascript.use_us_english_locale" static char* sSystemLocale; static char* sJSLocale; // Returns a pointer to the current JS Runtime. static JSRuntime* GetRuntime() { nsresult rv; nsCOMPtr<nsIJSRuntimeService> rts = do_GetService("@mozilla.org/js/xpc/RuntimeService;1", &rv); if (NS_FAILED(rv)) return NULL; JSRuntime* rt; rts->GetRuntime(&rt); return rt; } // If the USE_US_ENGLISH_LOCALE_PREF is active, set all locales to US English. // Otherwise, fall back to the default system and JS locales. static void UseUSEnglishLocalePrefChangedCallback(const char* /* pref */, void* /* closure */) { // Get a pointer to the default JS Runtime. JSRuntime* rt = GetRuntime(); if (rt) { // Read the pref to see if we will use US English locale. bool useUSEnglishLocale = mozilla::Preferences::GetBool(USE_US_ENGLISH_LOCALE_PREF, false); // Set the application-wide C-locale. Needed for Date.toLocaleFormat(). setlocale(LC_ALL, useUSEnglishLocale ? "C" : sSystemLocale); // Now override the JavaScript Runtime Locale that is used by the Intl API // as well as Date.toLocaleString, Number.toLocaleString, and String.localeCompare. JS_SetDefaultLocale(rt, useUSEnglishLocale ? "en-US" : sJSLocale); } } static void StartWatchingUseUSEnglishLocalePref() { // Get the default system locale. To be used if US English locale pref is deactivated. sSystemLocale = strdup(setlocale(LC_ALL,NULL)); // Store the default JavaScript locale. JSRuntime* rt = GetRuntime(); if (rt) { sJSLocale = strdup(JS_GetDefaultLocale(rt)); } // Now keep the locale updated with the current pref value. mozilla::Preferences::RegisterCallbackAndCall(UseUSEnglishLocalePrefChangedCallback, USE_US_ENGLISH_LOCALE_PREF); } static void StopWatchingUseUSEnglishLocalePref() { mozilla::Preferences::UnregisterCallback(UseUSEnglishLocalePrefChangedCallback, USE_US_ENGLISH_LOCALE_PREF); if (sSystemLocale) free(sSystemLocale); if (sJSLocale) JS_free(nullptr, sJSLocale); } } // anonymous namespace for locale hiding // Note that on OSX, aBinDirectory will point to .app/Contents/Resources/browser EXPORT_XPCOM_API(nsresult) NS_InitXPCOM2(nsIServiceManager** aResult, Loading Loading @@ -766,6 +830,8 @@ NS_InitXPCOM2(nsIServiceManager** aResult, mozilla::eventtracer::Init(); #endif // Start watching the "javascript.use_us_english_locale" pref. StartWatchingUseUSEnglishLocalePref(); return NS_OK; } Loading Loading @@ -1038,6 +1104,8 @@ ShutdownXPCOM(nsIServiceManager* aServMgr) delete sExitManager; sExitManager = nullptr; StopWatchingUseUSEnglishLocalePref(); Omnijar::CleanUp(); HangMonitor::Shutdown(); Loading