Skip to content
This repository has been archived by the owner on May 10, 2024. It is now read-only.

Commit

Permalink
Fix #4775: Message Token Leak Fix (#4776)
Browse files Browse the repository at this point in the history
  • Loading branch information
Brandon-T committed Jan 4, 2022
1 parent f377344 commit b0ada4f
Show file tree
Hide file tree
Showing 5 changed files with 145 additions and 124 deletions.
5 changes: 5 additions & 0 deletions Client/Frontend/Browser/PlaylistHelper.swift
Original file line number Diff line number Diff line change
Expand Up @@ -224,6 +224,11 @@ extension PlaylistHelper: UIGestureRecognizerDelegate {

extension PlaylistHelper {
static func getCurrentTime(webView: WKWebView, nodeTag: String, completion: @escaping (Double) -> Void) {
guard UUID(uuidString: nodeTag) != nil else {
log.error("Unsanitized NodeTag.")
return
}

let token = UserScriptManager.securityTokenString
let javascript = String(format: "window.__firefox__.mediaCurrentTimeFromTag_%@('%@')", token, nodeTag)

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,92 +4,94 @@

"use strict";

const mediaPublisherOrigins = [
'https://www.twitch.tv', 'https://m.twitch.tv', 'https://player.twitch.tv',
'https://www.youtube.com', 'https://m.youtube.com',
'https://vimeo.com',
]
(function(){
const mediaPublisherOrigins = [
'https://www.twitch.tv', 'https://m.twitch.tv', 'https://player.twitch.tv',
'https://www.youtube.com', 'https://m.youtube.com',
'https://vimeo.com',
]

if (mediaPublisherOrigins.includes(document.location.origin) && webkit.messageHandlers.rewardsReporting) {
install();
}

function install() {
function sendMessage(method, url, data, referrerUrl) {
webkit.messageHandlers.rewardsReporting.postMessage({"securitytoken": SECURITY_TOKEN, "data": {
method: method === undefined ? "GET" : method,
url: url,
data: (data === undefined || data instanceof Blob) ? null : data,
referrerUrl: referrerUrl === undefined ? null : referrerUrl,
}});
if (mediaPublisherOrigins.includes(document.location.origin) && webkit.messageHandlers.rewardsReporting) {
install();
}

let originalOpen = XMLHttpRequest.prototype.open;
let originalSend = XMLHttpRequest.prototype.send;
let originalFetch = window.fetch;
let originalSendBeacon = navigator.sendBeacon;
let originalImageSrc = Object.getOwnPropertyDescriptor(Image.prototype, "src");

XMLHttpRequest.prototype.open = function(method, url) {
const listener = function() {
sendMessage(this._method, this.responseURL === null ? this._url : this.responseURL, this._data, this._ref);
};
this._method = method;
this._url = url;
this.addEventListener('load', listener, true);
this.addEventListener('error', listener, true);
return originalOpen.apply(this, arguments);
};

XMLHttpRequest.prototype.send = function(body) {
this._ref = null;
this._data = body;
if (body instanceof Document) {
this._ref = body.referrer;
this._data = null;
function install() {
function sendMessage(method, url, data, referrerUrl) {
webkit.messageHandlers.rewardsReporting.postMessage({"securitytoken": SECURITY_TOKEN, "data": {
method: method === undefined ? "GET" : method,
url: url,
data: (data === undefined || data instanceof Blob) ? null : data,
referrerUrl: referrerUrl === undefined ? null : referrerUrl,
}});
}
return originalSend.apply(this, arguments);
};

let originalOpen = XMLHttpRequest.prototype.open;
let originalSend = XMLHttpRequest.prototype.send;
let originalFetch = window.fetch;
let originalSendBeacon = navigator.sendBeacon;
let originalImageSrc = Object.getOwnPropertyDescriptor(Image.prototype, "src");

XMLHttpRequest.prototype.open = function(method, url) {
const listener = function() {
sendMessage(this._method, this.responseURL === null ? this._url : this.responseURL, this._data, this._ref);
};
this._method = method;
this._url = url;
this.addEventListener('load', listener, true);
this.addEventListener('error', listener, true);
return originalOpen.apply(this, arguments);
};

XMLHttpRequest.prototype.send = function(body) {
this._ref = null;
this._data = body;
if (body instanceof Document) {
this._ref = body.referrer;
this._data = null;
}
return originalSend.apply(this, arguments);
};

window.fetch = function(resource, options) {
const args = arguments
const url = resource instanceof Request ? resource.url : resource
const method = options != null ? options.method : 'GET'
const body = options != null ? options.body : null
const referrer = options != null ? options.referrer : null
window.fetch = function(resource, options) {
const args = arguments
const url = resource instanceof Request ? resource.url : resource
const method = options != null ? options.method : 'GET'
const body = options != null ? options.body : null
const referrer = options != null ? options.referrer : null

return new Promise(function(resolve, reject) {
originalFetch.apply(this, args)
.then(function(response) {
sendMessage(method, url, body, referrer);
resolve(response);
})
.catch(function(error) {
sendMessage(method, url, body, referrer);
reject(error);
})
});
};
return new Promise(function(resolve, reject) {
originalFetch.apply(this, args)
.then(function(response) {
sendMessage(method, url, body, referrer);
resolve(response);
})
.catch(function(error) {
sendMessage(method, url, body, referrer);
reject(error);
})
});
};

navigator.sendBeacon = function(url, data) {
sendMessage("POST", url, data);
return originalSendBeacon.apply(this, arguments);
};

delete Image.prototype.src;
Object.defineProperty(Image.prototype, "src", {
get: function() {
return originalImageSrc.get.call(this);
},
set: function(value) {
const listener = function() {
sendMessage("GET", this.src);
navigator.sendBeacon = function(url, data) {
sendMessage("POST", url, data);
return originalSendBeacon.apply(this, arguments);
};
this.addEventListener('load', listener, true);
this.addEventListener('error', listener, true);
originalImageSrc.set.call(this, value);
},
enumerable: true,
configurable: true
});
}

delete Image.prototype.src;
Object.defineProperty(Image.prototype, "src", {
get: function() {
return originalImageSrc.get.call(this);
},
set: function(value) {
const listener = function() {
sendMessage("GET", this.src);
};
this.addEventListener('load', listener, true);
this.addEventListener('error', listener, true);
originalImageSrc.set.call(this, value);
},
enumerable: true,
configurable: true
});
}
})();
4 changes: 4 additions & 0 deletions Client/Frontend/UserContent/UserScripts/FullscreenHelper.js
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,10 @@ if (!isFullscreenSupportedNatively && videosSupportFullscreen && !/mobile/i.test
return false;
};

HTMLElement.prototype.requestFullscreen.toString = function() {
return "function () { [native code]; }";
};

Object.defineProperty(document, 'fullscreenEnabled', {
get: function() {
return true;
Expand Down
12 changes: 10 additions & 2 deletions Client/Frontend/UserContent/UserScripts/Playlist.js
Original file line number Diff line number Diff line change
Expand Up @@ -352,15 +352,23 @@ window.__firefox__.includeOnce("Playlist", function() {
if (key.toLowerCase() == 'src') {
$<notifyNode>(this);
}
}
};

HTMLVideoElement.prototype.setAttribute.toString = function() {
return "function () { [native code] }";
};

var setAudioAttribute = HTMLAudioElement.prototype.setAttribute;
HTMLAudioElement.prototype.setAttribute = function(key, value) {
setAudioAttribute.call(this, key, value);
if (key.toLowerCase() == 'src') {
$<notifyNode>(this);
}
}
};

HTMLAudioElement.prototype.setAttribute.toString = function() {
return "function () { [native code] }";
};

// When the page is idle
// Fetch static video and audio elements
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,46 +4,48 @@

"use strict";

if (webkit.messageHandlers.adsMediaReporting) {
install();
}

function install() {
function sendMessage(playing) {
webkit.messageHandlers.adsMediaReporting.postMessage({"securitytoken": SECURITY_TOKEN, "data": {playing}});
}

function checkVideoNode(node) {
if (node.constructor.name == "HTMLVideoElement") {
hookVideoFunctions();
(function(){
if (webkit.messageHandlers.adsMediaReporting) {
install();
}
}

function mediaPaused() {
sendMessage(false)
}

function mediaPlaying() {
sendMessage(true)
}

function getVideoElements() {
return document.querySelectorAll('video')
}

function hookVideoFunctions() {
getVideoElements().forEach(function (item) {
item.addEventListener('pause', mediaPaused, false);
item.addEventListener('playing', mediaPlaying, false);
});
}

var observer = new MutationObserver(function (mutations) {
mutations.forEach(function (mutation) {
mutation.addedNodes.forEach(function (node) {
checkVideoNode(node);

function install() {
function sendMessage(playing) {
webkit.messageHandlers.adsMediaReporting.postMessage({"securitytoken": SECURITY_TOKEN, "data": {playing}});
}

function checkVideoNode(node) {
if (node.constructor.name == "HTMLVideoElement") {
hookVideoFunctions();
}
}

function mediaPaused() {
sendMessage(false)
}

function mediaPlaying() {
sendMessage(true)
}

function getVideoElements() {
return document.querySelectorAll('video')
}

function hookVideoFunctions() {
getVideoElements().forEach(function (item) {
item.addEventListener('pause', mediaPaused, false);
item.addEventListener('playing', mediaPlaying, false);
});
}

var observer = new MutationObserver(function (mutations) {
mutations.forEach(function (mutation) {
mutation.addedNodes.forEach(function (node) {
checkVideoNode(node);
});
});
});
});
});
observer.observe(document, {subtree: true, childList: true });
}
observer.observe(document, {subtree: true, childList: true });
}
})()

0 comments on commit b0ada4f

Please sign in to comment.