Placeholders for MSE on Chromium too.

This commit is contained in:
hackademix 2019-11-11 10:29:36 +01:00
parent 53bf224e84
commit 118eb535aa
1 changed files with 73 additions and 45 deletions

View File

@ -1,28 +1,5 @@
if (typeof exportFunction === "function" && "MediaSource" in window) ns.on("capabilities", event => {
debug("Media Hook", document.URL, document.documentElement && document.documentElement.innerHTML, ns.capabilities); // DEV_ONLY
let mediaBlocker = !ns.allows("media");
let unpatched = new Map();
function patch(obj, methodName, replacement) {
let methods = unpatched.get(obj) || {};
methods[methodName] = obj[methodName];
exportFunction(replacement, obj, {defineAs: methodName});
unpatched.set(obj, methods);
}
let urlMap = new WeakMap();
patch(window.URL, "createObjectURL", function(o, ...args) {
let url = unpatched.get(window.URL).createObjectURL.call(this, o, ...args);
if (o instanceof MediaSource) {
let urls = urlMap.get(o);
if (!urls) urlMap.set(o, urls = new Set());
urls.add(url);
}
return url;
});
patch(window.MediaSource.prototype, "addSourceBuffer", function(mime, ...args) {
let ms = this;
let urls = urlMap.get(ms);
if ("MediaSource" in window) {
let notify = allowed => {
let request = {
id: "noscript-media",
type: "media",
@ -30,26 +7,77 @@ if (typeof exportFunction === "function" && "MediaSource" in window) ns.on("capa
documentUrl: document.URL,
embeddingDocument: true,
};
seen.record({policyType: "media", request, allowed: false});
seen.record({policyType: "media", request, allowed});
debug("MSE notification", document.URL); // DEV_ONLY
notifyPage();
if (mediaBlocker) {
let exposedMime = `${mime} (MSE)`;
setTimeout(() => {
let me = Array.from(document.querySelectorAll("video,audio"))
.find(e => e.srcObject === ms || urls && urls.has(e.src));
if (!me) return;
try {
let ph = PlaceHolder.create("media", request);
ph.replace(me);
PlaceHolder.listen();
} catch (e) {
error(e);
}
}, 0);
throw new Error(`${exposedMime} blocked by NoScript`);
return request;
};
let createPlaceholder = (mediaElement, request) => {
try {
let ph = PlaceHolder.create("media", request);
ph.replace(mediaElement);
PlaceHolder.listen();
debug("MSE placeholder for %o", mediaElement); // DEV_ONLY
} catch (e) {
error(e);
}
};
return unpatched.get(window.MediaSource.prototype).addSourceBuffer.call(ms, mime, ...args);
});
});
if (typeof exportFunction === "function") {
// Mozilla
let mediablocker = true;
ns.on("capabilities", e => {
mediaBlocker = !ns.allows("media");
});
let unpatched = new Map();
function patch(obj, methodName, replacement) {
let methods = unpatched.get(obj) || {};
methods[methodName] = obj[methodName];
exportFunction(replacement, obj, {defineAs: methodName});
unpatched.set(obj, methods);
}
let urlMap = new WeakMap();
patch(window.URL, "createObjectURL", function(o, ...args) {
let url = unpatched.get(window.URL).createObjectURL.call(this, o, ...args);
if (o instanceof MediaSource) {
let urls = urlMap.get(o);
if (!urls) urlMap.set(o, urls = new Set());
urls.add(url);
}
return url;
});
patch(window.MediaSource.prototype, "addSourceBuffer", function(mime, ...args) {
let ms = this;
let urls = urlMap.get(ms);
let request = notify(!mediaBlocker);
if (mediaBlocker) {
let exposedMime = `${mime} (MSE)`;
setTimeout(() => {
let me = Array.from(document.querySelectorAll("video,audio"))
.find(e => e.srcObject === ms || urls && urls.has(e.src));
if (me) createPlaceholder(me, request);
}, 0);
throw new Error(`${exposedMime} blocked by NoScript`);
}
return unpatched.get(window.MediaSource.prototype).addSourceBuffer.call(ms, mime, ...args);
});
} else if ("SecurityPolicyViolationEvent" in window) {
// Chromium
addEventListener("securitypolicyviolation", e => {
if (!e.isTrusted || ns.allows("media")) return;
let {blockedURI, violatedDirective} = e;
if (blockedURI.startsWith("blob") && violatedDirective.startsWith("media-src")) {
let request = notify(false);
for (let me of document.querySelectorAll("video,audio")) {
if (!(me.src || me.currentSrc) || me.src.startsWith("blob")) {
createPlaceholder(me, request);
}
}
}
}, true);
}
}