Commit ac6d26b2 authored by Leo Tenenbaum's avatar Leo Tenenbaum Committed by Pier Angelo Vendrame
Browse files

Bug 2040704 - Respect privacy.spoof_english in datetime input validation...

Bug 2040704 - Respect privacy.spoof_english in datetime input validation messages. r=timhuang,dom-core,hsivonen

Differential Revision: https://phabricator.services.mozilla.com/D301531
parent d58de249
Loading
Loading
Loading
Loading
+6 −8
Original line number Diff line number Diff line
@@ -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(
+16 −0
Original line number Diff line number Diff line
@@ -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.
+2 −0
Original line number Diff line number Diff line
@@ -51,3 +51,5 @@ support-files = [
  "empty.html",
  "image_yellow.png",
]

["browser_validationmessage_spoof_english.js"]
+86 −0
Original line number Diff line number Diff line
/* 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;
});
+17 −2
Original line number Diff line number Diff line
@@ -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();
Loading