Commit fdef2783 authored by Arthur Edelstein's avatar Arthur Edelstein Committed by Georg Koppen
Browse files

Bug #5926: Allow JS locale to be set to English/C.

parent de975c21
Loading
Loading
Loading
Loading
+1 −0
Original line number Diff line number Diff line
@@ -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]
+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>
+7 −0
Original line number Diff line number Diff line
@@ -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)
{
+9 −0
Original line number Diff line number Diff line
@@ -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.
 */
+68 −0
Original line number Diff line number Diff line
@@ -8,6 +8,7 @@

#include "mozilla/Atomics.h"
#include "mozilla/Poison.h"
#include "mozilla/Preferences.h"
#include "mozilla/XPCOM.h"
#include "nsXULAppAPI.h"

@@ -43,6 +44,8 @@
#include "nsSupportsPrimitives.h"
#include "nsConsoleService.h"

#include "nsIJSRuntimeService.h"

#include "nsComponentManager.h"
#include "nsCategoryManagerUtils.h"
#include "nsIServiceManager.h"
@@ -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,
@@ -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;
}

@@ -1038,6 +1104,8 @@ ShutdownXPCOM(nsIServiceManager* aServMgr)
  delete sExitManager;
  sExitManager = nullptr;

  StopWatchingUseUSEnglishLocalePref();

  Omnijar::CleanUp();

  HangMonitor::Shutdown();