morgan pushed to branch tor-browser-140.2.0esr-15.0-1 at The Tor Project / Applications / Tor Browser

Commits:

17 changed files:

Changes:

  • dom/base/nsContentUtils.cpp
    ... ... @@ -2844,7 +2844,7 @@ bool nsContentUtils::ShouldResistFingerprinting_dangerous(
    2844 2844
       }
    
    2845 2845
     
    
    2846 2846
       // Web extension principals are also excluded
    
    2847
    -  if (BasePrincipal::Cast(aPrincipal)->AddonPolicy()) {
    
    2847
    +  if (NS_IsMainThread() && BasePrincipal::Cast(aPrincipal)->AddonPolicy()) {
    
    2848 2848
         MOZ_LOG(nsContentUtils::ResistFingerprintingLog(), LogLevel::Debug,
    
    2849 2849
                 ("Inside ShouldResistFingerprinting(nsIPrincipal*)"
    
    2850 2850
                  " and AddonPolicy said false"));
    

  • dom/media/webcodecs/VideoFrame.cpp
    ... ... @@ -1423,7 +1423,7 @@ JSObject* VideoFrame::WrapObject(JSContext* aCx,
    1423 1423
     
    
    1424 1424
     /* static */
    
    1425 1425
     bool VideoFrame::PrefEnabled(JSContext* aCx, JSObject* aObj) {
    
    1426
    -  return StaticPrefs::dom_media_webcodecs_enabled() ||
    
    1426
    +  return nsRFPService::ExposeWebCodecsAPI(aCx, aObj) &&
    
    1427 1427
              StaticPrefs::dom_media_webcodecs_image_decoder_enabled();
    
    1428 1428
     }
    
    1429 1429
     
    

  • dom/media/webcodecs/test/mochitest.toml
    ... ... @@ -16,4 +16,13 @@ scheme = "https"
    16 16
     ["test_imageDecoder_desiredSize.html"]
    
    17 17
     scheme = "https"
    
    18 18
     
    
    19
    +["test_rfp_api_disabling_disabled.html"]
    
    20
    +scheme = "https"
    
    21
    +
    
    22
    +["test_rfp_api_disabling_enabled.html"]
    
    23
    +scheme = "https"
    
    24
    +
    
    25
    +["test_rfp_api_disabling_exemption.html"]
    
    26
    +scheme = "https"
    
    27
    +
    
    19 28
     ["test_videoFrame_mismatched_codedSize.html"]

  • dom/media/webcodecs/test/test_rfp_api_disabling_disabled.html
    1
    +<!DOCTYPE html>
    
    2
    +<html>
    
    3
    +<head>
    
    4
    +<title></title>
    
    5
    +<script src="/tests/SimpleTest/SimpleTest.js"></script>
    
    6
    +<link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" />
    
    7
    +</head>
    
    8
    +<body>
    
    9
    +<script>
    
    10
    +const apis = [
    
    11
    +  "AudioData",
    
    12
    +  "AudioDecoder",
    
    13
    +  "AudioEncoder",
    
    14
    +  "EncodedAudioChunk",
    
    15
    +  "EncodedVideoChunk",
    
    16
    +  "ImageDecoder",
    
    17
    +  "ImageTrack",
    
    18
    +  "ImageTrackList",
    
    19
    +  "VideoColorSpace",
    
    20
    +  "VideoDecoder",
    
    21
    +  "VideoEncoder",
    
    22
    +  "VideoFrame",
    
    23
    +];
    
    24
    +
    
    25
    +function enabledAPIs() {
    
    26
    +  return apis.filter(api => typeof window[api] !== "undefined");
    
    27
    +}
    
    28
    +
    
    29
    +function enabledAPIsWorker() {
    
    30
    +  const code = `
    
    31
    +  onmessage = e => {
    
    32
    +    const apis = ${JSON.stringify(apis)};
    
    33
    +    postMessage(apis.filter(api => typeof self[api] !== "undefined"));
    
    34
    +  };`;
    
    35
    +  const blob = new Blob([code], { type: "application/javascript" });
    
    36
    +  const worker = new Worker(URL.createObjectURL(blob));
    
    37
    +
    
    38
    +  return new Promise((resolve) => {
    
    39
    +    worker.addEventListener("message", async (e) => {
    
    40
    +      worker.terminate();
    
    41
    +      resolve(e.data);
    
    42
    +    });
    
    43
    +
    
    44
    +    worker.postMessage({});
    
    45
    +  });
    
    46
    +}
    
    47
    +
    
    48
    +add_setup(async () => {
    
    49
    +  await SpecialPowers.pushPrefEnv({
    
    50
    +    set: [
    
    51
    +      ["dom.media.webcodecs.enabled", true],
    
    52
    +      ["dom.media.webcodecs.image-decoder.enabled", true]
    
    53
    +    ],
    
    54
    +  });
    
    55
    +});
    
    56
    +
    
    57
    +add_task(async () => {
    
    58
    +  is(enabledAPIs().length, apis.length, true, "All WebCodecs APIs should be enabled");
    
    59
    +  is(
    
    60
    +    (await enabledAPIsWorker()).length,
    
    61
    +    apis.length,
    
    62
    +    "All WebCodecs APIs should be enabled in workers too"
    
    63
    +  );
    
    64
    +});
    
    65
    +</script>
    
    66
    +</body>
    
    67
    +</html>

  • dom/media/webcodecs/test/test_rfp_api_disabling_enabled.html
    1
    +<!DOCTYPE html>
    
    2
    +<html>
    
    3
    +<head>
    
    4
    +<title></title>
    
    5
    +<script src="/tests/SimpleTest/SimpleTest.js"></script>
    
    6
    +<link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" />
    
    7
    +</head>
    
    8
    +<body>
    
    9
    +<script>
    
    10
    +const apis = [
    
    11
    +  "AudioData",
    
    12
    +  "AudioDecoder",
    
    13
    +  "AudioEncoder",
    
    14
    +  "EncodedAudioChunk",
    
    15
    +  "EncodedVideoChunk",
    
    16
    +  "ImageDecoder",
    
    17
    +  "ImageTrack",
    
    18
    +  "ImageTrackList",
    
    19
    +  "VideoColorSpace",
    
    20
    +  "VideoDecoder",
    
    21
    +  "VideoEncoder",
    
    22
    +  "VideoFrame",
    
    23
    +];
    
    24
    +
    
    25
    +function enabledAPIs() {
    
    26
    +  return apis.filter(api => typeof window[api] !== "undefined");
    
    27
    +}
    
    28
    +
    
    29
    +function enabledAPIsWorker() {
    
    30
    +  const code = `
    
    31
    +  onmessage = e => {
    
    32
    +    const apis = ${JSON.stringify(apis)};
    
    33
    +    postMessage(apis.filter(api => typeof self[api] !== "undefined"));
    
    34
    +  };`;
    
    35
    +  const blob = new Blob([code], { type: "application/javascript" });
    
    36
    +  const worker = new Worker(URL.createObjectURL(blob));
    
    37
    +
    
    38
    +  return new Promise((resolve) => {
    
    39
    +    worker.addEventListener("message", async (e) => {
    
    40
    +      worker.terminate();
    
    41
    +      resolve(e.data);
    
    42
    +    });
    
    43
    +
    
    44
    +    worker.postMessage({});
    
    45
    +  });
    
    46
    +}
    
    47
    +
    
    48
    +add_setup(async () => {
    
    49
    +  await SpecialPowers.pushPrefEnv({
    
    50
    +    set: [
    
    51
    +      ["dom.media.webcodecs.enabled", true],
    
    52
    +      ["dom.media.webcodecs.image-decoder.enabled", true],
    
    53
    +      ["privacy.fingerprintingProtection", true],
    
    54
    +      ["privacy.fingerprintingProtection.overrides", "-AllTargets,+WebCodecs"],
    
    55
    +    ],
    
    56
    +  });
    
    57
    +});
    
    58
    +
    
    59
    +add_task(async () => {
    
    60
    +  is(enabledAPIs().length, 0, true, "All WebCodecs APIs should be disabled");
    
    61
    +  is(
    
    62
    +    (await enabledAPIsWorker()).length,
    
    63
    +    0,
    
    64
    +    "All WebCodecs APIs should be disabled in workers too"
    
    65
    +  );
    
    66
    +});
    
    67
    +</script>
    
    68
    +</body>
    
    69
    +</html>

  • dom/media/webcodecs/test/test_rfp_api_disabling_exemption.html
    1
    +<!DOCTYPE html>
    
    2
    +<html>
    
    3
    +<head>
    
    4
    +<title></title>
    
    5
    +<script src="/tests/SimpleTest/SimpleTest.js"></script>
    
    6
    +<link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" />
    
    7
    +</head>
    
    8
    +<body>
    
    9
    +<script>
    
    10
    +const apis = [
    
    11
    +  "AudioData",
    
    12
    +  "AudioDecoder",
    
    13
    +  "AudioEncoder",
    
    14
    +  "EncodedAudioChunk",
    
    15
    +  "EncodedVideoChunk",
    
    16
    +  "ImageDecoder",
    
    17
    +  "ImageTrack",
    
    18
    +  "ImageTrackList",
    
    19
    +  "VideoColorSpace",
    
    20
    +  "VideoDecoder",
    
    21
    +  "VideoEncoder",
    
    22
    +  "VideoFrame",
    
    23
    +];
    
    24
    +
    
    25
    +function enabledAPIs() {
    
    26
    +  return apis.filter(api => typeof window[api] !== "undefined");
    
    27
    +}
    
    28
    +
    
    29
    +function enabledAPIsWorker() {
    
    30
    +  const code = `
    
    31
    +  onmessage = e => {
    
    32
    +    const apis = ${JSON.stringify(apis)};
    
    33
    +    postMessage(apis.filter(api => typeof self[api] !== "undefined"));
    
    34
    +  };`;
    
    35
    +  const blob = new Blob([code], { type: "application/javascript" });
    
    36
    +  const worker = new Worker(URL.createObjectURL(blob));
    
    37
    +
    
    38
    +  return new Promise((resolve) => {
    
    39
    +    worker.addEventListener("message", async (e) => {
    
    40
    +      worker.terminate();
    
    41
    +      resolve(e.data);
    
    42
    +    });
    
    43
    +
    
    44
    +    worker.postMessage({});
    
    45
    +  });
    
    46
    +}
    
    47
    +
    
    48
    +add_setup(async () => {
    
    49
    +  await SpecialPowers.pushPrefEnv({
    
    50
    +    set: [
    
    51
    +      ["dom.media.webcodecs.enabled", true],
    
    52
    +      ["dom.media.webcodecs.image-decoder.enabled", true],
    
    53
    +      ["privacy.fingerprintingProtection", true],
    
    54
    +      ["privacy.fingerprintingProtection.overrides", "-AllTargets,+WebCodecs"],
    
    55
    +      ["privacy.resistFingerprinting.exemptedDomains", location.hostname]
    
    56
    +    ],
    
    57
    +  });
    
    58
    +});
    
    59
    +
    
    60
    +add_task(async () => {
    
    61
    +  is(enabledAPIs().length, apis.length, true, "All WebCodecs APIs should be disabled");
    
    62
    +  is(
    
    63
    +    (await enabledAPIsWorker()).length,
    
    64
    +    apis.length,
    
    65
    +    "All WebCodecs APIs should be disabled in workers too"
    
    66
    +  );
    
    67
    +});
    
    68
    +</script>
    
    69
    +</body>
    
    70
    +</html>

  • dom/webidl/AudioData.webidl
    ... ... @@ -9,7 +9,7 @@
    9 9
     
    
    10 10
     // [Serializable, Transferable] are implemented without adding attributes here,
    
    11 11
     // but directly with {Read,Write}StructuredClone and Transfer/FromTransfered.
    
    12
    -[Exposed=(Window,DedicatedWorker), Pref="dom.media.webcodecs.enabled"]
    
    12
    +[Exposed=(Window,DedicatedWorker), Func="nsRFPService::ExposeWebCodecsAPI"]
    
    13 13
     interface AudioData {
    
    14 14
       [Throws]
    
    15 15
       constructor(AudioDataInit init);
    

  • dom/webidl/AudioDecoder.webidl
    ... ... @@ -7,7 +7,7 @@
    7 7
      * https://w3c.github.io/webcodecs/#audiodecoder
    
    8 8
      */
    
    9 9
     
    
    10
    -[Exposed=(Window,DedicatedWorker), SecureContext, Pref="dom.media.webcodecs.enabled"]
    
    10
    +[Exposed=(Window,DedicatedWorker), SecureContext, Func="nsRFPService::ExposeWebCodecsAPI"]
    
    11 11
     interface AudioDecoder : EventTarget {
    
    12 12
       [Throws]
    
    13 13
       constructor(AudioDecoderInit init);
    

  • dom/webidl/AudioEncoder.webidl
    ... ... @@ -42,7 +42,7 @@ dictionary OpusEncoderConfig {
    42 42
       boolean usedtx = false;
    
    43 43
     };
    
    44 44
     
    
    45
    -[Exposed=(Window,DedicatedWorker), SecureContext, Pref="dom.media.webcodecs.enabled"]
    
    45
    +[Exposed=(Window,DedicatedWorker), SecureContext, Func="nsRFPService::ExposeWebCodecsAPI"]
    
    46 46
     interface AudioEncoder : EventTarget {
    
    47 47
       [Throws]
    
    48 48
       constructor(AudioEncoderInit init);
    

  • dom/webidl/EncodedAudioChunk.webidl
    ... ... @@ -8,7 +8,7 @@
    8 8
      */
    
    9 9
     
    
    10 10
     // [Serializable] is implemented without adding attribute here.
    
    11
    -[Exposed=(Window,DedicatedWorker), Pref="dom.media.webcodecs.enabled"]
    
    11
    +[Exposed=(Window,DedicatedWorker), Func="nsRFPService::ExposeWebCodecsAPI"]
    
    12 12
     interface EncodedAudioChunk {
    
    13 13
       [Throws]
    
    14 14
       constructor(EncodedAudioChunkInit init);
    

  • dom/webidl/EncodedVideoChunk.webidl
    ... ... @@ -8,7 +8,7 @@
    8 8
      */
    
    9 9
     
    
    10 10
     // [Serializable] is implemented without adding attribute here.
    
    11
    -[Exposed=(Window,DedicatedWorker), Pref="dom.media.webcodecs.enabled"]
    
    11
    +[Exposed=(Window,DedicatedWorker), Func="nsRFPService::ExposeWebCodecsAPI"]
    
    12 12
     interface EncodedVideoChunk {
    
    13 13
       [Throws]
    
    14 14
       constructor(EncodedVideoChunkInit init);
    

  • dom/webidl/ImageDecoder.webidl
    ... ... @@ -30,7 +30,7 @@ dictionary ImageDecodeResult {
    30 30
     
    
    31 31
     [Exposed=(Window,DedicatedWorker),
    
    32 32
      SecureContext,
    
    33
    - Pref="dom.media.webcodecs.image-decoder.enabled"]
    
    33
    + Func="nsRFPService::ExposeWebCodecsAPIImageDecoder"]
    
    34 34
     interface ImageTrack {
    
    35 35
       readonly attribute boolean animated;
    
    36 36
       readonly attribute unsigned long frameCount;
    
    ... ... @@ -40,7 +40,7 @@ interface ImageTrack {
    40 40
     
    
    41 41
     [Exposed=(Window,DedicatedWorker),
    
    42 42
      SecureContext,
    
    43
    - Pref="dom.media.webcodecs.image-decoder.enabled"]
    
    43
    + Func="nsRFPService::ExposeWebCodecsAPIImageDecoder"]
    
    44 44
     interface ImageTrackList {
    
    45 45
       getter ImageTrack (unsigned long index);
    
    46 46
     
    
    ... ... @@ -52,7 +52,7 @@ interface ImageTrackList {
    52 52
     
    
    53 53
     [Exposed=(Window,DedicatedWorker),
    
    54 54
      SecureContext,
    
    55
    - Pref="dom.media.webcodecs.image-decoder.enabled"]
    
    55
    + Func="nsRFPService::ExposeWebCodecsAPIImageDecoder"]
    
    56 56
     interface ImageDecoder {
    
    57 57
       [Throws]
    
    58 58
       constructor(ImageDecoderInit init);
    

  • dom/webidl/VideoDecoder.webidl
    ... ... @@ -7,7 +7,7 @@
    7 7
      * https://w3c.github.io/webcodecs/#videodecoder
    
    8 8
      */
    
    9 9
     
    
    10
    -[Exposed=(Window,DedicatedWorker), SecureContext, Pref="dom.media.webcodecs.enabled"]
    
    10
    +[Exposed=(Window,DedicatedWorker), SecureContext, Func="nsRFPService::ExposeWebCodecsAPI"]
    
    11 11
     interface VideoDecoder : EventTarget {
    
    12 12
       [Throws]
    
    13 13
       constructor(VideoDecoderInit init);
    

  • dom/webidl/VideoEncoder.webidl
    ... ... @@ -12,7 +12,7 @@
    12 12
      * commented with a link of the document in which the member is listed.
    
    13 13
      */
    
    14 14
     
    
    15
    -[Exposed=(Window,DedicatedWorker), SecureContext, Pref="dom.media.webcodecs.enabled"]
    
    15
    +[Exposed=(Window,DedicatedWorker), SecureContext, Func="nsRFPService::ExposeWebCodecsAPI"]
    
    16 16
     interface VideoEncoder : EventTarget {
    
    17 17
       [Throws]
    
    18 18
       constructor(VideoEncoderInit init);
    

  • toolkit/components/resistfingerprinting/RFPTargets.inc
    ... ... @@ -101,6 +101,7 @@ ITEM_VALUE(JSLocalePrompt, 67)
    101 101
     ITEM_VALUE(ScreenAvailToResolution,     68)
    
    102 102
     ITEM_VALUE(UseHardcodedFontSubstitutes, 69)
    
    103 103
     ITEM_VALUE(DiskStorageLimit,            70)
    
    104
    +ITEM_VALUE(WebCodecs,                   71)
    
    104 105
     
    
    105 106
     
    
    106 107
     // !!! Don't forget to update kDefaultFingerprintingProtections in nsRFPService.cpp
    

  • toolkit/components/resistfingerprinting/nsRFPService.cpp
    ... ... @@ -2697,3 +2697,48 @@ uint64_t nsRFPService::GetSpoofedStorageLimit() {
    2697 2697
     
    
    2698 2698
       return limit;
    
    2699 2699
     }
    
    2700
    +
    
    2701
    +/* static */
    
    2702
    +bool nsRFPService::ExposeWebCodecsAPI(JSContext* aCx, JSObject* aObj) {
    
    2703
    +  if (!StaticPrefs::dom_media_webcodecs_enabled()) {
    
    2704
    +    return false;
    
    2705
    +  }
    
    2706
    +
    
    2707
    +  return !IsWebCodecsRFPTargetEnabled(aCx);
    
    2708
    +}
    
    2709
    +
    
    2710
    +/* static */
    
    2711
    +bool nsRFPService::ExposeWebCodecsAPIImageDecoder(JSContext* aCx,
    
    2712
    +                                                  JSObject* aObj) {
    
    2713
    +  if (!StaticPrefs::dom_media_webcodecs_image_decoder_enabled()) {
    
    2714
    +    return false;
    
    2715
    +  }
    
    2716
    +
    
    2717
    +  return !IsWebCodecsRFPTargetEnabled(aCx);
    
    2718
    +}
    
    2719
    +
    
    2720
    +/* static */
    
    2721
    +bool nsRFPService::IsWebCodecsRFPTargetEnabled(JSContext* aCx) {
    
    2722
    +  if (!nsContentUtils::ShouldResistFingerprinting("Efficiency check",
    
    2723
    +                                                  RFPTarget::WebCodecs)) {
    
    2724
    +    return false;
    
    2725
    +  }
    
    2726
    +
    
    2727
    +  // We know that the RFPTarget::WebCodecs is enabled, check if principal
    
    2728
    +  // is exempted.
    
    2729
    +
    
    2730
    +  // VideoFrame::PrefEnabled function can be called without a JSContext.
    
    2731
    +  if (!aCx) {
    
    2732
    +    return true;
    
    2733
    +  }
    
    2734
    +
    
    2735
    +  // Once bug 1973966 is resolved, we can replace this section with just
    
    2736
    +  // nsIPrincipal* principal = nsContentUtils::SubjectPrincipal(aCx);
    
    2737
    +  JS::Realm* realm = js::GetContextRealm(aCx);
    
    2738
    +  MOZ_ASSERT(realm);
    
    2739
    +  JSPrincipals* principals = JS::GetRealmPrincipals(realm);
    
    2740
    +  nsIPrincipal* principal = nsJSPrincipals::get(principals);
    
    2741
    +
    
    2742
    +  return nsContentUtils::ShouldResistFingerprinting_dangerous(
    
    2743
    +      principal, "Principal is the best context we have", RFPTarget::WebCodecs);
    
    2744
    +}

  • toolkit/components/resistfingerprinting/nsRFPService.h
    ... ... @@ -416,6 +416,9 @@ class nsRFPService final : public nsIObserver, public nsIRFPService {
    416 416
     
    
    417 417
       static uint64_t GetSpoofedStorageLimit();
    
    418 418
     
    
    419
    +  static bool ExposeWebCodecsAPI(JSContext* aCx, JSObject* aObj);
    
    420
    +  static bool ExposeWebCodecsAPIImageDecoder(JSContext* aCx, JSObject* aObj);
    
    421
    +
    
    419 422
      private:
    
    420 423
       nsresult Init();
    
    421 424
     
    
    ... ... @@ -527,6 +530,8 @@ class nsRFPService final : public nsIObserver, public nsIRFPService {
    527 530
       static bool IsTargetActiveForMode(RFPTarget aTarget,
    
    528 531
                                         FingerprintingProtectionType aMode);
    
    529 532
     
    
    533
    +  static bool IsWebCodecsRFPTargetEnabled(JSContext* aCx);
    
    534
    +
    
    530 535
       static nsCString* sExemptedDomainsLowercase;
    
    531 536
     };
    
    532 537