mirror of
https://github.com/mozilla/gecko-dev.git
synced 2025-02-25 11:58:55 +00:00
Bug 1390465: Load all subtitles in RFP. r=tjr
This patch targets non-js mode. By fetching everything, the website can't tell what language is being used. Trying to protect js enabled mode would be impossible as websites can just use a custom player and record usage as they wish. Differential Revision: https://phabricator.services.mozilla.com/D223636
This commit is contained in:
parent
ee2988bdf0
commit
52c07c5f9d
@ -93,7 +93,8 @@ class WindowDestroyObserver final : public nsIObserver {
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
if (innerID == mInnerID) {
|
||||
if (mTrackElement) {
|
||||
mTrackElement->CancelChannelAndListener();
|
||||
// Window is being destroyed, cancel without checking for RFP.
|
||||
mTrackElement->CancelChannelAndListener(false);
|
||||
}
|
||||
UnRegisterWindowDestroyObserver();
|
||||
}
|
||||
@ -128,7 +129,8 @@ HTMLTrackElement::~HTMLTrackElement() {
|
||||
if (mWindowDestroyObserver) {
|
||||
mWindowDestroyObserver->UnRegisterWindowDestroyObserver();
|
||||
}
|
||||
CancelChannelAndListener();
|
||||
// Track element is being destroyed, cancel without checking for RFP.
|
||||
CancelChannelAndListener(false);
|
||||
}
|
||||
|
||||
NS_IMPL_ELEMENT_CLONE(HTMLTrackElement)
|
||||
@ -250,11 +252,18 @@ void HTMLTrackElement::MaybeDispatchLoadResource() {
|
||||
|
||||
// step2, if the text track's text track mode is not set to one of hidden or
|
||||
// showing, then return.
|
||||
if (mTrack->Mode() == TextTrackMode::Disabled) {
|
||||
bool resistFingerprinting = ShouldResistFingerprinting(RFPTarget::WebVTT);
|
||||
if (mTrack->Mode() == TextTrackMode::Disabled && !resistFingerprinting) {
|
||||
LOG("Do not load resource for disable track");
|
||||
return;
|
||||
}
|
||||
|
||||
// We need to do this check in order to prevent
|
||||
// HonorUserPreferencesForTrackSelection from loading the text track twice.
|
||||
if (resistFingerprinting && ReadyState() == TextTrackReadyState::Loading) {
|
||||
return;
|
||||
}
|
||||
|
||||
// step3, if the text track's track element does not have a media element as a
|
||||
// parent, return.
|
||||
if (!mMediaParent) {
|
||||
@ -294,7 +303,8 @@ void HTMLTrackElement::LoadResource(RefPtr<WebVTTListener>&& aWebVTTListener) {
|
||||
NS_ENSURE_TRUE_VOID(NS_SUCCEEDED(rv));
|
||||
LOG("Trying to load from src=%s", NS_ConvertUTF16toUTF8(src).get());
|
||||
|
||||
CancelChannelAndListener();
|
||||
// Prevent canceling the channel and listener if RFP is enabled.
|
||||
CancelChannelAndListener(true);
|
||||
|
||||
// According to
|
||||
// https://www.w3.org/TR/html5/embedded-content-0.html#sourcing-out-of-band-text-tracks
|
||||
@ -470,7 +480,11 @@ void HTMLTrackElement::DispatchTrustedEvent(const nsAString& aName) {
|
||||
Cancelable::eNo);
|
||||
}
|
||||
|
||||
void HTMLTrackElement::CancelChannelAndListener() {
|
||||
void HTMLTrackElement::CancelChannelAndListener(bool aCheckRFP) {
|
||||
if (aCheckRFP && ShouldResistFingerprinting(RFPTarget::WebVTT)) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (mChannel) {
|
||||
mChannel->CancelWithReason(NS_BINDING_ABORTED,
|
||||
"HTMLTrackElement::CancelChannelAndListener"_ns);
|
||||
@ -484,6 +498,15 @@ void HTMLTrackElement::CancelChannelAndListener() {
|
||||
}
|
||||
}
|
||||
|
||||
bool HTMLTrackElement::ShouldResistFingerprinting(RFPTarget aRfpTarget) {
|
||||
Document* doc = OwnerDoc();
|
||||
if (!doc) {
|
||||
return nsContentUtils::ShouldResistFingerprinting("Null document",
|
||||
aRfpTarget);
|
||||
}
|
||||
return doc->ShouldResistFingerprinting(aRfpTarget);
|
||||
}
|
||||
|
||||
void HTMLTrackElement::AfterSetAttr(int32_t aNameSpaceID, nsAtom* aName,
|
||||
const nsAttrValue* aValue,
|
||||
const nsAttrValue* aOldValue,
|
||||
|
@ -98,7 +98,9 @@ class HTMLTrackElement final : public nsGenericHTMLElement {
|
||||
void DispatchTrustedEvent(const nsAString& aName);
|
||||
void DispatchTestEvent(const nsAString& aName);
|
||||
|
||||
void CancelChannelAndListener();
|
||||
void CancelChannelAndListener(bool aCheckRFP);
|
||||
|
||||
bool ShouldResistFingerprinting(RFPTarget aRfpTarget);
|
||||
|
||||
// Only load resource for the non-disabled track with media parent.
|
||||
void MaybeDispatchLoadResource();
|
||||
|
@ -114,7 +114,8 @@ WebVTTListener::OnStopRequest(nsIRequest* aRequest, nsresult aStatus) {
|
||||
mElement->SetReadyState(TextTrackReadyState::Loaded);
|
||||
}
|
||||
|
||||
mElement->CancelChannelAndListener();
|
||||
// Prevent canceling the channel and listener if RFP is enabled.
|
||||
mElement->CancelChannelAndListener(true);
|
||||
|
||||
return aStatus;
|
||||
}
|
||||
|
124
dom/media/webvtt/test/mochitest/basicvtt-server.sjs
Normal file
124
dom/media/webvtt/test/mochitest/basicvtt-server.sjs
Normal file
@ -0,0 +1,124 @@
|
||||
// This file is a simple "server" for test_webvtt_resistfingerprinting.html
|
||||
|
||||
// You can request a VTT file by setting the `request` parameter to `vtt` and
|
||||
// providing an `id` parameter. Id parameter is used to track how many times
|
||||
// a specific test has requested the file. Please don't use the same id for
|
||||
// multiple tests.
|
||||
|
||||
// You can also request the number of times a specific test has requested the
|
||||
// file by setting the `request` parameter to `count` and providing an `id`
|
||||
// parameter.
|
||||
|
||||
const vtt = `WEBVTT
|
||||
REGION
|
||||
id:testOne lines:2 width:30%
|
||||
REGION
|
||||
id:testTwo lines:4 width:20%
|
||||
|
||||
1
|
||||
00:00.500 --> 00:00.700 region:testOne
|
||||
This
|
||||
|
||||
2
|
||||
00:01.200 --> 00:02.400 region:testTwo
|
||||
Is
|
||||
|
||||
2.5
|
||||
00:02.000 --> 00:03.500 region:testOne
|
||||
(Over here?!)
|
||||
|
||||
3
|
||||
00:02.710 --> 00:02.910
|
||||
A
|
||||
|
||||
4
|
||||
00:03.217 --> 00:03.989
|
||||
Test
|
||||
|
||||
5
|
||||
00:03.217 --> 00:03.989
|
||||
And more!
|
||||
`;
|
||||
|
||||
// stolen from server-stream-download.sjs# and they stole it from file_blocked_script.sjs
|
||||
function setGlobalState(data, key) {
|
||||
const x = {
|
||||
data,
|
||||
QueryInterface(_iid) {
|
||||
return this;
|
||||
},
|
||||
};
|
||||
x.wrappedJSObject = x;
|
||||
setObjectState(key, x);
|
||||
}
|
||||
|
||||
function getGlobalState(key) {
|
||||
let data;
|
||||
getObjectState(key, function (x) {
|
||||
data = x && x.wrappedJSObject.data;
|
||||
});
|
||||
return data;
|
||||
}
|
||||
|
||||
const requestCounter = (() => {
|
||||
const keyPrefix = "vtt-request-counter-";
|
||||
|
||||
return {
|
||||
recordRequest(id) {
|
||||
const key = keyPrefix + id;
|
||||
const count = getGlobalState(key) || 0;
|
||||
setGlobalState(count + 1, key);
|
||||
},
|
||||
getRequestCount(id) {
|
||||
const key = keyPrefix + id;
|
||||
return getGlobalState(key) || 0;
|
||||
},
|
||||
};
|
||||
})();
|
||||
|
||||
// We need this for test-verify jobs. It runs the test
|
||||
// multiple times and we need to know how many times
|
||||
// the test has been run because global state is not
|
||||
// reset between runs.
|
||||
const iterationCounter = (() => {
|
||||
const keyPrefix = "vtt-request-iteration-counter-";
|
||||
|
||||
return {
|
||||
recordIteration() {
|
||||
const count = getGlobalState(keyPrefix) || 0;
|
||||
setGlobalState(count + 1, keyPrefix);
|
||||
},
|
||||
getIterationCount() {
|
||||
return getGlobalState(keyPrefix) || 0;
|
||||
},
|
||||
};
|
||||
})();
|
||||
|
||||
function handleRequest(aRequest, aResponse) {
|
||||
aResponse.setHeader("Access-Control-Allow-Origin", "*", false);
|
||||
|
||||
const params = aRequest.queryString
|
||||
.split("&")
|
||||
.map(command => command.split("="))
|
||||
.reduce((acc, [key, value]) => {
|
||||
acc[key] = value;
|
||||
return acc;
|
||||
}, {});
|
||||
|
||||
if (params.request === "vtt") {
|
||||
requestCounter.recordRequest(params.id);
|
||||
aResponse.setStatusLine(aRequest.httpVersion, 200);
|
||||
aResponse.setHeader("Content-Type", "text/vtt", false);
|
||||
aResponse.write(vtt);
|
||||
} else if (params.request === "count") {
|
||||
aResponse.setStatusLine(aRequest.httpVersion, 200);
|
||||
aResponse.write(requestCounter.getRequestCount(params.id));
|
||||
} else if (params.request === "newIteration") {
|
||||
iterationCounter.recordIteration();
|
||||
aResponse.setStatusLine(aRequest.httpVersion, 200);
|
||||
aResponse.write(iterationCounter.getIterationCount());
|
||||
} else {
|
||||
aResponse.setStatusLine(aRequest.httpVersion, 400);
|
||||
aResponse.write(aRequest.queryString);
|
||||
}
|
||||
}
|
@ -72,6 +72,12 @@ skip-if = ["true"]
|
||||
|
||||
["test_webvtt_positionalign.html"]
|
||||
|
||||
["test_webvtt_resistfingerprinting.html"]
|
||||
support-files = [
|
||||
"basicvtt-server.sjs",
|
||||
]
|
||||
run-sequentially = "An extension having the same id is installed/uninstalled in different tests"
|
||||
|
||||
["test_webvtt_seeking.html"]
|
||||
|
||||
["test_webvtt_update_display_after_adding_or_removing_cue.html"]
|
||||
|
@ -0,0 +1,76 @@
|
||||
<!DOCTYPE HTML>
|
||||
<html>
|
||||
<head>
|
||||
<meta charset='utf-8'>
|
||||
<title>WebVTT: ResistFingerprinting</title>
|
||||
<script src="/tests/SimpleTest/SimpleTest.js"></script>
|
||||
<link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
|
||||
</head>
|
||||
<body>
|
||||
<div id="content">
|
||||
</div>
|
||||
<template id="video">
|
||||
<video width="600" height="400" controls onloadeddata="handleOnLoadedData()">
|
||||
<source src="gizmo.mp4" type="video/mp4">
|
||||
<track label="VTT1" kind="subtitles" srclang="en" src="basicvtt-server.sjs?request=vtt&id=test_webvtt_resistfingerprinting.html" />
|
||||
<track label="VTT2" kind="subtitles" srclang="es" src="basicvtt-server.sjs?request=vtt&id=test_webvtt_resistfingerprinting.html" />
|
||||
<track label="VTT3" kind="subtitles" srclang="tr" src="basicvtt-server.sjs?request=vtt&id=test_webvtt_resistfingerprinting.html" default />
|
||||
</video>
|
||||
</template>
|
||||
<script class="testbody" type="text/javascript">
|
||||
SimpleTest.waitForExplicitFinish();
|
||||
SimpleTest.requestFlakyTimeout("Need to wait for all VTT files to be loaded");
|
||||
|
||||
let iteration = "0";
|
||||
async function startTest() {
|
||||
await SpecialPowers.pushPrefEnv({
|
||||
"set": [
|
||||
["privacy.resistFingerprinting", true]
|
||||
]
|
||||
});
|
||||
|
||||
iteration = await fetch("basicvtt-server.sjs?request=newIteration")
|
||||
.then(response => response.text());
|
||||
|
||||
const video = document.getElementById("video").content.cloneNode(true);
|
||||
video.querySelectorAll("track").forEach(track => {
|
||||
track.src = track.src + iteration;
|
||||
});
|
||||
document.getElementById("content").appendChild(video);
|
||||
}
|
||||
|
||||
async function handleOnLoadedData() {
|
||||
// Wait for 5 minutes at most
|
||||
for (let i = 0; i < 5 * 60; i++) {
|
||||
const shouldEnd = await fetch("basicvtt-server.sjs?request=count&id=test_webvtt_resistfingerprinting.html" + iteration)
|
||||
.then(response => response.text())
|
||||
.then(text => {
|
||||
info("Number of VTT files loaded: " + text);
|
||||
const num = +text;
|
||||
if (num === 3) {
|
||||
ok(true, "All VTT files are loaded");
|
||||
return true
|
||||
}
|
||||
if (num > 3) {
|
||||
ok(false, "Too many VTT files are loaded");
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}).catch(error => {
|
||||
ok(false, "Failed to fetch count: " + error);
|
||||
return true;
|
||||
});
|
||||
if (shouldEnd) {
|
||||
break;
|
||||
}
|
||||
await new Promise(resolve => setTimeout(resolve, 1000));
|
||||
}
|
||||
|
||||
await SpecialPowers.popPrefEnv();
|
||||
SimpleTest.finish();
|
||||
}
|
||||
|
||||
onload = startTest;
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
@ -93,6 +93,7 @@ ITEM_VALUE(SiteSpecificZoom, 1llu << 60)
|
||||
// Are font visibility restrictions applied when resolving a CSS <generic-family>?
|
||||
// (This may block the fonts selected in Preferences from actually being used.)
|
||||
ITEM_VALUE(FontVisibilityRestrictGenerics, 1llu << 61)
|
||||
ITEM_VALUE(WebVTT, 1llu << 62)
|
||||
|
||||
// !!! Don't forget to update kDefaultFingerprintingProtections in nsRFPService.cpp
|
||||
// if necessary.
|
||||
|
Loading…
x
Reference in New Issue
Block a user