@eyeo/snippets
Version:
eye/o snippets for Ads blocker
1,673 lines (1,397 loc) • 99.2 kB
JavaScript
/*!
* This file is part of eyeo's Anti-Circumvention Snippets module (@eyeo/snippets),
* Copyright (C) 2006-present eyeo GmbH
*
* @eyeo/snippets is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 3 as
* published by the Free Software Foundation.
*
* @eyeo/snippets is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with @eyeo/snippets. If not, see <http://www.gnu.org/licenses/>.
*/
const callback = (environment, ...filters) => {
/*!
* This file is part of eyeo's Anti-Circumvention Snippets module (@eyeo/snippets),
* Copyright (C) 2006-present eyeo GmbH
*
* @eyeo/snippets is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 3 as
* published by the Free Software Foundation.
*
* @eyeo/snippets is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with @eyeo/snippets. If not, see <http://www.gnu.org/licenses/>.
*/
const $$1 = Proxy;
const {apply: a, bind: b, call: c} = Function;
const apply$2 = c.bind(a);
const bind = c.bind(b);
const call = c.bind(c);
const callerHandler = {
get(target, name) {
return bind(c, target[name]);
}
};
const caller = target => new $$1(target, callerHandler);
const proxy = (source, target) => new $$1(source, {
apply: (_, self, args) => apply$2(target, self, args)
});
const handler$2 = {
get(target, name) {
return bind(target[name], target);
}
};
const bound = target => new $$1(target, handler$2);
const {
assign: assign$1,
defineProperties: defineProperties$1,
freeze: freeze$1,
getOwnPropertyDescriptor: getOwnPropertyDescriptor$3,
getOwnPropertyDescriptors: getOwnPropertyDescriptors$1,
getPrototypeOf
} = bound(Object);
const {hasOwnProperty} = caller({});
const {species} = Symbol;
const handler$1 = {
get(target, name) {
const Native = target[name];
class Secure extends Native {}
const proto = getOwnPropertyDescriptors$1(Native.prototype);
delete proto.constructor;
freeze$1(defineProperties$1(Secure.prototype, proto));
const statics = getOwnPropertyDescriptors$1(Native);
delete statics.length;
delete statics.prototype;
statics[species] = {value: Secure};
return freeze$1(defineProperties$1(Secure, statics));
}
};
const secure = target => new $$1(target, handler$1);
const libEnvironment = typeof environment !== "undefined" ? environment :
{};
if (typeof globalThis === "undefined")
window.globalThis = window;
const {apply: apply$1, ownKeys} = bound(Reflect);
const worldEnvDefined = "world" in libEnvironment;
const isIsolatedWorld = worldEnvDefined && libEnvironment.world === "ISOLATED";
const isMainWorld = worldEnvDefined && libEnvironment.world === "MAIN";
const chromeObjAvailable = typeof chrome === "object" && !!chrome.runtime;
const browserObjAvailable = typeof browser === "object" && !!browser.runtime;
const isExtensionContext$2 = !isMainWorld &&
(isIsolatedWorld || chromeObjAvailable || browserObjAvailable);
const copyIfExtension = value => isExtensionContext$2 ?
value :
create(value, getOwnPropertyDescriptors(value));
const {
create,
defineProperties,
defineProperty,
freeze,
getOwnPropertyDescriptor: getOwnPropertyDescriptor$2,
getOwnPropertyDescriptors
} = bound(Object);
const invokes = bound(globalThis);
const classes = isExtensionContext$2 ? globalThis : secure(globalThis);
const {Map: Map$c, RegExp: RegExp$3, Set: Set$3, WeakMap: WeakMap$6, WeakSet: WeakSet$4} = classes;
const augment = (source, target, method = null) => {
const known = ownKeys(target);
for (const key of ownKeys(source)) {
if (known.includes(key))
continue;
const descriptor = getOwnPropertyDescriptor$2(source, key);
if (method && "value" in descriptor) {
const {value} = descriptor;
if (typeof value === "function")
descriptor.value = method(value);
}
defineProperty(target, key, descriptor);
}
};
const primitive = name => {
const Super = classes[name];
class Class extends Super {}
const {toString, valueOf} = Super.prototype;
defineProperties(Class.prototype, {
toString: {value: toString},
valueOf: {value: valueOf}
});
const type = name.toLowerCase();
const method = callback => function() {
const result = apply$1(callback, this, arguments);
return typeof result === type ? new Class(result) : result;
};
augment(Super, Class, method);
augment(Super.prototype, Class.prototype, method);
return Class;
};
const variables$3 = freeze({
frozen: new WeakMap$6(),
hidden: new WeakSet$4(),
iframePropertiesToAbort: {
read: new Set$3(),
write: new Set$3()
},
abortedIframes: new WeakMap$6()
});
const startsCapitalized = new RegExp$3("^[A-Z]");
const extensionApi = (
isExtensionContext$2 && (
(chromeObjAvailable && chrome) ||
(browserObjAvailable && browser)
)
) || void 0;
var env = new Proxy(new Map$c([
["chrome", extensionApi],
["browser", extensionApi],
["isExtensionContext", isExtensionContext$2],
["variables", variables$3],
["console", copyIfExtension(console)],
["document", globalThis.document],
["JSON", copyIfExtension(JSON)],
["Map", Map$c],
["Math", copyIfExtension(Math)],
["Number", isExtensionContext$2 ? Number : primitive("Number")],
["RegExp", RegExp$3],
["Set", Set$3],
["String", isExtensionContext$2 ? String : primitive("String")],
["WeakMap", WeakMap$6],
["WeakSet", WeakSet$4],
["MouseEvent", MouseEvent]
]), {
get(map, key) {
if (map.has(key))
return map.get(key);
let value = globalThis[key];
if (typeof value === "function")
value = (startsCapitalized.test(key) ? classes : invokes)[key];
map.set(key, value);
return value;
},
has(map, key) {
return map.has(key);
}
});
class WeakValue {
has() { return false; }
set() {}
}
const helpers = {WeakSet, WeakMap, WeakValue};
const {apply} = Reflect;
function transformOnce (callback) { const {WeakSet, WeakMap, WeakValue} = (this || helpers);
const ws = new WeakSet;
const wm = new WeakMap;
const wv = new WeakValue;
return function (any) {
if (ws.has(any))
return any;
if (wm.has(any))
return wm.get(any);
if (wv.has(any))
return wv.get(any);
const value = apply(callback, this, arguments);
ws.add(value);
if (value !== any)
(typeof any === 'object' && any ? wm : wv).set(any, value);
return value;
};
}
const {Map: Map$b, WeakMap: WeakMap$5, WeakSet: WeakSet$3, setTimeout} = env;
let cleanup = true;
let cleanUpCallback = map => {
map.clear();
cleanup = !cleanup;
};
var transformer = transformOnce.bind({
WeakMap: WeakMap$5,
WeakSet: WeakSet$3,
WeakValue: class extends Map$b {
set(key, value) {
if (cleanup) {
cleanup = !cleanup;
setTimeout(cleanUpCallback, 0, this);
}
return super.set(key, value);
}
}
});
const {concat, includes, join, reduce, unshift} = caller([]);
const globals = secure(globalThis);
const {
Map: Map$a,
WeakMap: WeakMap$4
} = globals;
const map = new Map$a;
const descriptors = target => {
const chain = [];
let current = target;
while (current) {
if (map.has(current))
unshift(chain, map.get(current));
else {
const descriptors = getOwnPropertyDescriptors$1(current);
map.set(current, descriptors);
unshift(chain, descriptors);
}
current = getPrototypeOf(current);
}
unshift(chain, {});
return apply$2(assign$1, null, chain);
};
const chain = source => {
const target = typeof source === 'function' ? source.prototype : source;
const chained = descriptors(target);
const handler = {
get(target, key) {
if (key in chained) {
const {value, get} = chained[key];
if (get)
return call(get, target);
if (typeof value === 'function')
return bind(value, target);
}
return target[key];
},
set(target, key, value) {
if (key in chained) {
const {set} = chained[key];
if (set) {
call(set, target, value);
return true;
}
}
target[key] = value;
return true;
}
};
return target => new $$1(target, handler);
};
const {
isExtensionContext: isExtensionContext$1,
Array: Array$7,
Number: Number$1,
String: String$1,
Object: Object$e
} = env;
const {isArray} = Array$7;
const {getOwnPropertyDescriptor: getOwnPropertyDescriptor$1, setPrototypeOf: setPrototypeOf$1} = Object$e;
const {toString: toString$1} = Object$e.prototype;
const {slice} = String$1.prototype;
const getBrand = value => call(slice, call(toString$1, value), 8, -1);
const {get: nodeType} = getOwnPropertyDescriptor$1(Node.prototype, "nodeType");
const chained = isExtensionContext$1 ? {} : {
Attr: chain(Attr),
CanvasRenderingContext2D: chain(CanvasRenderingContext2D),
CSSStyleDeclaration: chain(CSSStyleDeclaration),
Document: chain(Document),
Element: chain(Element),
HTMLCanvasElement: chain(HTMLCanvasElement),
HTMLElement: chain(HTMLElement),
HTMLImageElement: chain(HTMLImageElement),
HTMLScriptElement: chain(HTMLScriptElement),
MutationRecord: chain(MutationRecord),
Node: chain(Node),
ShadowRoot: chain(ShadowRoot),
get CSS2Properties() {
return chained.CSSStyleDeclaration;
}
};
const upgrade = (value, hint) => {
if (hint !== "Element" && hint in chained)
return chained[hint](value);
if (isArray(value))
return setPrototypeOf$1(value, Array$7.prototype);
const brand = getBrand(value);
if (brand in chained)
return chained[brand](value);
if (brand in env)
return setPrototypeOf$1(value, env[brand].prototype);
if ("nodeType" in value) {
switch (call(nodeType, value)) {
case 1:
if (!(hint in chained))
throw new Error("unknown hint " + hint);
return chained[hint](value);
case 2:
return chained.Attr(value);
case 3:
return chained.Node(value);
case 9:
return chained.Document(value);
}
}
throw new Error("unknown brand " + brand);
};
var $ = isExtensionContext$1 ?
value => (value === window || value === globalThis ? env : value) :
transformer((value, hint = "Element") => {
if (value === window || value === globalThis)
return env;
switch (typeof value) {
case "object":
return value && upgrade(value, hint);
case "string":
return new String$1(value);
case "number":
return new Number$1(value);
default:
throw new Error("unsupported value");
}
});
const handler = {
get(target, name) {
const context = target;
while (!hasOwnProperty(target, name))
target = getPrototypeOf(target);
const {get, set} = getOwnPropertyDescriptor$3(target, name);
return function () {
return arguments.length ?
apply$2(set, context, arguments) :
call(get, context);
};
}
};
const accessor = target => new $$1(target, handler);
let {Math: Math$2, setInterval: setInterval$1, performance} = $(window);
const noopProfile = {
mark() {},
end() {},
toString() {
return "{mark(){},end(){}}";
}
};
let inactive = true;
function setProfile() {
inactive = false;
}
function profile(id, rate = 10) {
if (inactive)
return noopProfile;
function processSamples() {
let samples = $([]);
for (let {name, duration} of performance.getEntriesByType("measure"))
samples.push({name, duration});
if (samples.length)
performance.clearMeasures();
}
if (!profile[id]) {
profile[id] = setInterval$1(processSamples,
Math$2.round(60000 / Math$2.min(60, rate)));
}
return {
mark() {
performance.mark(id);
},
end(clear = false) {
performance.measure(id, id);
const measures = performance.getEntriesByName(id, "measure");
const measureObj = measures.length > 0 ?
measures[measures.length - 1] : null;
console.log("PROFILER:", measureObj);
performance.clearMarks(id);
if (clear) {
clearInterval(profile[id]);
delete profile[id];
processSamples();
}
}
};
}
let debugging = false;
function debug() {
return debugging;
}
function setDebug() {
debugging = true;
}
const {console: console$4} = $(window);
const noop = () => {};
function log(...args) {
let {mark, end} = profile("log");
if (debug()) {
const logArgs = ["%c DEBUG", "font-weight: bold;"];
const isErrorIndex = args.indexOf("error");
const isWarnIndex = args.indexOf("warn");
const isSuccessIndex = args.indexOf("success");
const isInfoIndex = args.indexOf("info");
if (isErrorIndex !== -1) {
logArgs[0] += " - ERROR";
logArgs[1] += "color: red; border:2px solid red";
$(args).splice(isErrorIndex, 1);
}
else if (isWarnIndex !== -1) {
logArgs[0] += " - WARNING";
logArgs[1] += "color: orange; border:2px solid orange ";
$(args).splice(isWarnIndex, 1);
}
else if (isSuccessIndex !== -1) {
logArgs[0] += " - SUCCESS";
logArgs[1] += "color: green; border:2px solid green";
$(args).splice(isSuccessIndex, 1);
}
else if (isInfoIndex !== -1) {
logArgs[1] += "color: black;";
$(args).splice(isInfoIndex, 1);
}
$(args).unshift(...logArgs);
}
mark();
console$4.log(...args);
end();
}
function getDebugger(name) {
return bind(debug() ? log : noop, null, name);
}
let {Array: Array$6, Math: Math$1, RegExp: RegExp$2} = $(window);
function regexEscape(string) {
return $(string).replace(/[-/\\^$*+?.()|[\]{}]/g, "\\$&");
}
function toRegExp(pattern) {
let {length} = pattern;
if (length > 1 && pattern[0] === "/") {
let isCaseSensitive = pattern[length - 1] === "/";
if (isCaseSensitive || (length > 2 && $(pattern).endsWith("/i"))) {
let args = [$(pattern).slice(1, isCaseSensitive ? -1 : -2)];
if (!isCaseSensitive)
args.push("i");
return new RegExp$2(...args);
}
}
return new RegExp$2(regexEscape(pattern));
}
function randomId() {
return $(Math$1.floor(Math$1.random() * 2116316160 + 60466176)).toString(36);
}
function formatArguments(args) {
return $(Array$6.from(args)).map(arg => `'${arg}'`).join(" ");
}
let {
parseFloat,
variables: variables$2,
Array: Array$5,
Error: Error$9,
Map: Map$9,
Object: Object$d,
ReferenceError: ReferenceError$2,
Set: Set$2,
WeakMap: WeakMap$3
} = $(window);
let {onerror} = accessor(window);
let NodeProto$1 = Node.prototype;
let ElementProto$2 = Element.prototype;
let propertyAccessors = null;
function wrapPropertyAccess(object, property, descriptor,
setConfigurable = true) {
let $property = $(property);
let dotIndex = $property.indexOf(".");
if (dotIndex == -1) {
let currentDescriptor = Object$d.getOwnPropertyDescriptor(object, property);
if (currentDescriptor && !currentDescriptor.configurable)
return;
let newDescriptor = Object$d.assign({}, descriptor, {
configurable: setConfigurable
});
if (!currentDescriptor && !newDescriptor.get && newDescriptor.set) {
let propertyValue = object[property];
newDescriptor.get = () => propertyValue;
}
Object$d.defineProperty(object, property, newDescriptor);
return;
}
let name = $property.slice(0, dotIndex).toString();
property = $property.slice(dotIndex + 1).toString();
let value = object[name];
if (value && (typeof value == "object" || typeof value == "function"))
wrapPropertyAccess(value, property, descriptor);
let currentDescriptor = Object$d.getOwnPropertyDescriptor(object, name);
if (currentDescriptor && !currentDescriptor.configurable)
return;
if (!propertyAccessors)
propertyAccessors = new WeakMap$3();
if (!propertyAccessors.has(object))
propertyAccessors.set(object, new Map$9());
let properties = propertyAccessors.get(object);
if (properties.has(name)) {
properties.get(name).set(property, descriptor);
return;
}
let toBeWrapped = new Map$9([[property, descriptor]]);
properties.set(name, toBeWrapped);
Object$d.defineProperty(object, name, {
get: () => value,
set(newValue) {
value = newValue;
if (value && (typeof value == "object" || typeof value == "function")) {
for (let [prop, desc] of toBeWrapped)
wrapPropertyAccess(value, prop, desc);
}
},
configurable: setConfigurable
});
}
function overrideOnError(magic) {
let prev = onerror();
onerror((...args) => {
let message = args.length && args[0];
if (typeof message == "string" && $(message).includes(magic))
return true;
if (typeof prev == "function")
return apply$2(prev, this, args);
});
}
function abortOnRead(loggingPrefix, context,
property, formattedProperties = "",
setConfigurable = true) {
let debugLog = getDebugger(loggingPrefix);
if (!property) {
debugLog("error", "no property to abort on read");
return;
}
let rid = randomId();
function abort() {
debugLog("success", `${property} access aborted`, `\nFILTER: ${loggingPrefix} ${formattedProperties}`);
throw new ReferenceError$2(rid);
}
debugLog("info", `aborting on ${property} access`);
wrapPropertyAccess(context,
property,
{get: abort, set() {}},
setConfigurable);
overrideOnError(rid);
}
function abortOnWrite(loggingPrefix,
context, property,
formattedProperties = "",
setConfigurable = true) {
let debugLog = getDebugger(loggingPrefix);
if (!property) {
debugLog("error", "no property to abort on write");
return;
}
let rid = randomId();
function abort() {
debugLog("success", `setting ${property} aborted`, `\nFILTER: ${loggingPrefix} ${formattedProperties}`);
throw new ReferenceError$2(rid);
}
debugLog("info", `aborting when setting ${property}`);
wrapPropertyAccess(context, property, {set: abort}, setConfigurable);
overrideOnError(rid);
}
function abortOnIframe(
properties,
abortRead = false,
abortWrite = false
) {
let abortedIframes = variables$2.abortedIframes;
let iframePropertiesToAbort = variables$2.iframePropertiesToAbort;
const formattedPropertiesToLog = formatArguments(properties);
for (let frame of Array$5.from(window.frames)) {
if (abortedIframes.has(frame)) {
for (let property of properties) {
if (abortRead)
abortedIframes.get(frame).read.add({property, formattedProperties: formattedPropertiesToLog});
if (abortWrite)
abortedIframes.get(frame).write.add({property, formattedProperties: formattedPropertiesToLog});
}
}
}
for (let property of properties) {
if (abortRead)
iframePropertiesToAbort.read.add({property, formattedProperties: formattedPropertiesToLog});
if (abortWrite)
iframePropertiesToAbort.write.add({property, formattedProperties: formattedPropertiesToLog});
}
queryAndProxyIframe();
if (!abortedIframes.has(document)) {
abortedIframes.set(document, true);
addHooksOnDomAdditions(queryAndProxyIframe);
}
function queryAndProxyIframe() {
for (let frame of Array$5.from(window.frames)) {
if (!abortedIframes.has(frame)) {
abortedIframes.set(frame, {
read: new Set$2(iframePropertiesToAbort.read),
write: new Set$2(iframePropertiesToAbort.write)
});
}
let readProps = abortedIframes.get(frame).read;
if (readProps.size > 0) {
let props = Array$5.from(readProps);
readProps.clear();
for (let {property, formattedProperties} of props) {
abortOnRead("abort-on-iframe-property-read",
frame,
property,
formattedProperties);
}
}
let writeProps = abortedIframes.get(frame).write;
if (writeProps.size > 0) {
let props = Array$5.from(writeProps);
writeProps.clear();
for (let {property, formattedProperties} of props) {
abortOnWrite("abort-on-iframe-property-write",
frame,
property,
formattedProperties);
}
}
}
}
}
function addHooksOnDomAdditions(endCallback) {
let descriptor;
wrapAccess(NodeProto$1, ["appendChild", "insertBefore", "replaceChild"]);
wrapAccess(ElementProto$2, ["append", "prepend", "replaceWith", "after",
"before", "insertAdjacentElement",
"insertAdjacentHTML"]);
descriptor = getInnerHTMLDescriptor(ElementProto$2, "innerHTML");
wrapPropertyAccess(ElementProto$2, "innerHTML", descriptor);
descriptor = getInnerHTMLDescriptor(ElementProto$2, "outerHTML");
wrapPropertyAccess(ElementProto$2, "outerHTML", descriptor);
function wrapAccess(prototype, names) {
for (let name of names) {
let desc = getAppendChildDescriptor(prototype, name);
wrapPropertyAccess(prototype, name, desc);
}
}
function getAppendChildDescriptor(target, property) {
let currentValue = target[property];
return {
get() {
return function(...args) {
let result;
result = apply$2(currentValue, this, args);
endCallback && endCallback();
return result;
};
}
};
}
function getInnerHTMLDescriptor(target, property) {
let desc = Object$d.getOwnPropertyDescriptor(target, property);
let {set: prevSetter} = desc || {};
return {
set(val) {
let result;
result = call(prevSetter, this, val);
endCallback && endCallback();
return result;
}
};
}
}
let {Object: NativeObject} = window;
function findOwner(root, path) {
if (!(root instanceof NativeObject))
return;
let object = root;
let chain = $(path).split(".");
if (chain.length === 0)
return;
for (let i = 0; i < chain.length - 1; i++) {
let prop = chain[i];
if (!hasOwnProperty(object, prop))
return;
object = object[prop];
if (!(object instanceof NativeObject))
return;
}
let prop = chain[chain.length - 1];
if (hasOwnProperty(object, prop))
return [object, prop];
}
const decimals = $(/^\d+$/);
function overrideValue(value) {
switch (value) {
case "false":
return false;
case "true":
return true;
case "null":
return null;
case "noopFunc":
return () => {};
case "trueFunc":
return () => true;
case "falseFunc":
return () => false;
case "emptyArray":
return [];
case "emptyObj":
return {};
case "undefined":
return void 0;
case "":
return value;
default:
if (decimals.test(value))
return parseFloat(value);
throw new Error$9("[override-property-read snippet]: " +
`Value "${value}" is not valid.`);
}
}
let {HTMLScriptElement: HTMLScriptElement$1, Object: Object$c, ReferenceError: ReferenceError$1} = $(window);
let Script = Object$c.getPrototypeOf(HTMLScriptElement$1);
function abortCurrentInlineScript(api, search = null) {
const formattedArguments = formatArguments(arguments);
const debugLog = getDebugger("abort-current-inline-script");
const {mark, end} = profile("abort-current-inline-script");
const re = search ? toRegExp(search) : null;
const rid = randomId();
const us = $(document).currentScript;
let object = window;
const path = $(api).split(".");
const name = $(path).pop();
for (let node of $(path)) {
object = object[node];
if (
!object || !(typeof object == "object" || typeof object == "function")) {
debugLog("warn", path, " is not found");
return;
}
}
const {get: prevGetter, set: prevSetter} =
Object$c.getOwnPropertyDescriptor(object, name) || {};
let currentValue = object[name];
if (typeof currentValue === "undefined")
debugLog("warn", "The property", name, "doesn't exist yet. Check typos.");
const abort = () => {
const element = $(document).currentScript;
if (element instanceof Script &&
$(element, "HTMLScriptElement").src == "" &&
element != us &&
(!re || re.test($(element).textContent))) {
debugLog("success",
path,
" is aborted \n",
element,
"\nFILTER: abort-current-inline-script",
formattedArguments);
throw new ReferenceError$1(rid);
}
};
const descriptor = {
get() {
abort();
if (prevGetter)
return call(prevGetter, this);
return currentValue;
},
set(value) {
abort();
if (prevSetter)
call(prevSetter, this, value);
else
currentValue = value;
}
};
mark();
wrapPropertyAccess(object,
name,
descriptor);
end();
overrideOnError(rid);
}
function abortOnIframePropertyRead(...properties) {
const {mark, end} = profile("abort-on-iframe-property-read");
mark();
abortOnIframe(properties, true, false);
end();
}
function abortOnIframePropertyWrite(...properties) {
const {mark, end} = profile("abort-on-iframe-property-write");
mark();
abortOnIframe(properties, false, true);
end();
}
function abortOnPropertyRead(property, setConfigurable) {
const configurableFlag = !(setConfigurable === "false");
const formattedArguments = formatArguments(arguments);
const {mark, end} = profile("abort-on-property-read");
mark();
abortOnRead("abort-on-property-read",
window,
property,
formattedArguments,
configurableFlag);
end();
}
function abortOnPropertyWrite(property, setConfigurable) {
const formattedArguments = formatArguments(arguments);
const {mark, end} = profile("abort-on-property-write");
const configurableFlag = !(setConfigurable === "false");
mark();
abortOnWrite("abort-on-property-write",
window,
property,
formattedArguments,
configurableFlag);
end();
}
const {Error: Error$8, Object: Object$b, Array: Array$4, Map: Map$8} = $(window);
let arrayValues = null;
function hasMatchingProperty(val, needle, pathSegments) {
let current = val;
for (const segment of pathSegments) {
if (!current || !hasOwnProperty(current, segment))
return false;
current = current[segment];
}
if (typeof current === "string" || typeof current === "number"){
const currStr = current.toString();
return needle.test(currStr);
}
return false;
}
function arrayOverride(method, needle, returnValue = "false",
path) {
if (!method)
throw new Error$8("[array-override snippet]: Missing method to override.");
if (!needle)
throw new Error$8("[array-override snippet]: Missing needle.");
if (!arrayValues)
arrayValues = new Map$8();
let debugLog = getDebugger("array-override");
const {mark, end} = profile("array-override");
const formattedArgsToLog = formatArguments(arguments);
if (method === "push" && !arrayValues.has("push")) {
mark();
const {push} = Array$4.prototype;
arrayValues.set("push", $([]));
Object$b.defineProperty(window.Array.prototype, "push", {
value: proxy(push, function(val) {
const overrideVals = arrayValues.get("push");
for (const {needleRegex, pathSegments} of overrideVals) {
if (!pathSegments.length && (typeof val === "string" ||
typeof val === "number")) {
const valStr = val.toString();
if (valStr.match && valStr.match(needleRegex)) {
debugLog("success", `Array.push is ignored for needle: ${needleRegex}\nFILTER: array-override ${formattedArgsToLog}`);
return;
}
}
else if (pathSegments.length && typeof val === "object" &&
val !== null) {
if (hasMatchingProperty(val, needleRegex, pathSegments)) {
debugLog("success", `Array.push is ignored for object containing needle: ${needleRegex}\nFILTER: array-override ${formattedArgsToLog}`);
return;
}
}
}
return apply$2(push, this, arguments);
})
});
debugLog("info", "Wrapped Array.prototype.push");
end();
}
else if (method === "includes" && !arrayValues.has("includes")) {
mark();
const {includes} = Array$4.prototype;
arrayValues.set("includes", $([]));
Object$b.defineProperty(window.Array.prototype, "includes", {
value: proxy(includes, function(val) {
const overrideVals = arrayValues.get("includes");
for (const {needleRegex, retVal, pathSegments} of overrideVals) {
if (!pathSegments.length && (typeof val === "string" ||
typeof val === "number")) {
if (val.toString().match && val.toString().match(needleRegex)) {
debugLog("success", `Array.includes returned ${retVal} for ${needleRegex}\nFILTER: array-override ${formattedArgsToLog}`);
return retVal;
}
}
else if (pathSegments.length && typeof val === "object" &&
val !== null) {
if (hasMatchingProperty(val, needleRegex, pathSegments)) {
debugLog("success", `Array.includes returned ${retVal} for object containing ${needleRegex}\nFILTER: array-override ${formattedArgsToLog}`);
return retVal;
}
}
}
return apply$2(includes, this, arguments);
})
});
debugLog("info", "Wrapped Array.prototype.includes");
end();
}
else if (method === "forEach" && !arrayValues.has("forEach")) {
mark();
const {forEach} = Array$4.prototype;
arrayValues.set("forEach", $([]));
Object$b.defineProperty(window.Array.prototype, "forEach", {
value: proxy(forEach, function(callback, thisArg) {
const overrideVals = arrayValues.get("forEach");
const filteredCallback = function(item, index, array) {
for (const {needleRegex, pathSegments} of overrideVals) {
if (!pathSegments.length && (typeof item === "string" ||
typeof item === "number")) {
const itemStr = item.toString();
if (itemStr.match && itemStr.match(needleRegex)) {
debugLog("success", `Array.forEach skipped callback for item matching needle: ${needleRegex}\nFILTER: array-override ${formattedArgsToLog}`);
return;
}
}
else if (pathSegments.length && typeof item === "object" &&
item !== null) {
if (hasMatchingProperty(item, needleRegex, pathSegments)) {
debugLog("success", `Array.forEach skipped callback for object containing needle: ${needleRegex}\nFILTER: array-override ${formattedArgsToLog}`);
return;
}
}
}
return apply$2(callback, thisArg || this, [item, index, array]);
};
return apply$2(forEach, this, [filteredCallback, thisArg]);
})
});
debugLog("info", "Wrapped Array.prototype.forEach");
end();
}
const needleRegex = toRegExp(needle);
let pathSegments = [];
if (path)
pathSegments = path.split(".");
const overrideVals = arrayValues.get(method);
const retVal = returnValue === "true";
overrideVals.push({needleRegex, retVal, pathSegments});
arrayValues.set(method, overrideVals);
}
const {Array: Array$3, Blob, Error: Error$7, Object: Object$a, Reflect: Reflect$2} = $(window);
const blobRules = [];
function blobOverride(search, replacement = "", needle = null) {
if (!search) {
throw new Error$7(
"[blob-override snippet]: Missing parameter search."
);
}
const debugLog = getDebugger("blob-override");
const formattedArgsToLog = formatArguments(arguments);
const {mark, end} = profile("blob-override");
mark();
blobRules.push({
match: toRegExp(search),
replaceWith: replacement,
needle: needle ? toRegExp(needle) : null,
formattedArgs: formattedArgsToLog
});
if (blobRules.length > 1)
return;
const OriginalBlob = Blob;
function PatchedBlob(data, options = {}) {
if (Array$3.isArray(data)) {
data = $(data).map(chunk => {
if (typeof chunk !== "string")
return chunk;
let modified = $(chunk);
for (const rule of $(blobRules)) {
if (
(!rule.needle || rule.needle.test(modified)) &&
rule.match.test(modified)
) {
modified = modified.replace(rule.match, rule.replaceWith);
debugLog("success", `Replaced: ${rule.match} → ${rule.replaceWith},\nFILTER: blob-override ${rule.formattedArgs}`);
}
}
return modified;
});
}
const blob = Reflect$2.construct(OriginalBlob, [data, options]);
Object$a.setPrototypeOf(blob, PatchedBlob.prototype);
return blob;
}
PatchedBlob.prototype = OriginalBlob.prototype;
Object$a.setPrototypeOf(PatchedBlob, OriginalBlob);
window.Blob = PatchedBlob;
debugLog("info", "Wrapped Blob constructor in context ");
end();
}
let {Error: Error$6, URL: URL$2} = $(window);
let {cookie: documentCookies} = accessor(document);
function cookieRemover(cookie, autoRemoveCookie = false) {
if (!cookie)
throw new Error$6("[cookie-remover snippet]: No cookie to remove.");
const formattedArguments = formatArguments(arguments);
let debugLog = getDebugger("cookie-remover");
const {mark, end} = profile("cookie-remover");
let re = toRegExp(cookie);
if (!$(/^http|^about/).test(location.protocol)) {
debugLog("warn", "Snippet only works for http or https and about.");
return;
}
function getCookieMatches() {
const arr = $(documentCookies()).split(";");
return arr.filter(str => re.test($(str).split("=")[0]));
}
const mainLogic = () => {
debugLog("info", "Parsing cookies for matches");
mark();
for (const pair of $(getCookieMatches())) {
let $hostname = $(location.hostname);
if (!$hostname &&
$(location.ancestorOrigins) && $(location.ancestorOrigins[0]))
$hostname = new URL$2($(location.ancestorOrigins[0])).hostname;
const name = $(pair).split("=")[0];
const expires = "expires=Thu, 01 Jan 1970 00:00:00 GMT";
const path = "path=/";
const domainParts = $hostname.split(".");
for (let numDomainParts = domainParts.length;
numDomainParts > 0; numDomainParts--) {
const domain =
domainParts.slice(domainParts.length - numDomainParts).join(".");
documentCookies(`${$(name).trim()}=;${expires};${path};domain=${domain}`);
documentCookies(`${$(name).trim()}=;${expires};${path};domain=.${domain}`);
debugLog("success", `Set expiration date on ${name}`, "\nFILTER: cookie-remover", formattedArguments);
}
}
end();
};
mainLogic();
if (autoRemoveCookie) {
let lastCookie = getCookieMatches();
setInterval(() => {
let newCookie = getCookieMatches();
if (newCookie !== lastCookie) {
try {
mainLogic();
}
finally {
lastCookie = newCookie;
}
}
}, 1000);
}
}
const {Map: Map$7, Object: Object$9, Reflect: Reflect$1, WeakMap: WeakMap$2} = $(window);
const originalAddEventListener = window.EventTarget.prototype.addEventListener;
const originalRemoveEventListener = window.EventTarget.
prototype.removeEventListener;
const listenerMap = new WeakMap$2();
let eventOverrides = [];
function eventOverride(eventType,
mode,
needle = null) {
const formattedArgs = formatArguments(arguments);
const overrideConfig = {
eventType,
mode,
needle: needle ? toRegExp(needle) : null,
formattedArgs
};
if (!eventOverrides.includes(overrideConfig))
eventOverrides.push(overrideConfig);
if (eventOverrides.length > 1)
return;
let debugLog = getDebugger("[event-override]");
const {mark, end} = profile("event-override");
const addEventListenerDescriptor = Object$9.getOwnPropertyDescriptor(
window.EventTarget.prototype,
"addEventListener"
);
if (addEventListenerDescriptor.configurable) {
Object$9.defineProperty(window.EventTarget.prototype, "addEventListener", {
...addEventListenerDescriptor,
value: proxy(
originalAddEventListener,
function(type, listener, options) {
mark();
const filteredEvents = eventOverrides.filter(
ev => ev.eventType === type
);
if (!filteredEvents.length || type !== filteredEvents[0].eventType) {
end();
return apply$2(originalAddEventListener, this, arguments);
}
const disabledEvent = filteredEvents.find(
ev =>
(ev.mode === "disable") &&
(ev.needle ? ev.needle.test(listener.toString()) : true)
);
if (disabledEvent) {
debugLog("success", `Disabling ${disabledEvent.eventType} event, \nFILTER: event-override ${disabledEvent.formattedArgs}`);
end();
return;
}
const changedEvents = filteredEvents.filter(
ev =>
(ev.mode === "trusted") &&
(ev.needle ? ev.needle.test(listener.toString()) : true)
);
if (typeof listener !== "function" &&
!(listener && typeof listener.handleEvent === "function") ||
!changedEvents.length || type !== changedEvents[0].eventType) {
end();
return apply$2(originalAddEventListener, this, arguments);
}
const wrappedListener = function(originalEvent) {
const customEvent = new Proxy(originalEvent, {
get(target, prop) {
if (prop === "isTrusted") {
debugLog("success", `Providing trusted value for ${originalEvent.type} event`);
return true;
}
const val = Reflect$1.get(target, prop);
if (typeof val === "function") {
return function(...args) {
return apply$2(val, target, args);
};
}
return val;
}
});
if (typeof listener === "function")
return call(listener, this, customEvent);
return call(listener.handleEvent, listener, customEvent);
};
wrappedListener.originalListener = listener;
if (!listenerMap.has(listener))
listenerMap.set(listener, new Map$7());
listenerMap.get(listener).set(type, wrappedListener);
debugLog("info", `\nWrapping event listener for ${type}`);
end();
return apply$2(
originalAddEventListener,
this,
[type, wrappedListener, options]
);
})
});
}
const removeEventListenerDescriptor = Object$9.getOwnPropertyDescriptor(
window.EventTarget.prototype,
"removeEventListener"
);
if (removeEventListenerDescriptor.configurable) {
Object$9.defineProperty(window.EventTarget.prototype, "removeEventListener", {
...removeEventListenerDescriptor,
value: proxy(
originalRemoveEventListener,
function(type, listener, options) {
if (listener &&
listenerMap.has(listener) && listenerMap.get(listener).has(type)) {
const wrappedListener = listenerMap.get(listener).get(type);
listenerMap.get(listener).delete(type);
return apply$2(
originalRemoveEventListener,
this,
[type, wrappedListener, options]
);
}
return apply$2(originalRemoveEventListener, this, arguments);
})
});
}
debugLog("info", "Initialized event-override snippet");
}
let {
console: console$3,
document: document$2,
getComputedStyle,
isExtensionContext,
variables: variables$1,
Array: Array$2,
MutationObserver: MutationObserver$3,
Object: Object$8,
XPathEvaluator,
XPathExpression,
XPathResult
} = $(window);
const {querySelectorAll} = document$2;
const document$$ = querySelectorAll && bind(querySelectorAll, document$2);
function $openOrClosedShadowRoot(element, failSilently = false) {
try {
const shadowRoot = (navigator.userAgent.includes("Firefox")) ?
element.openOrClosedShadowRoot :
browser.dom.openOrClosedShadowRoot(element);
if (shadowRoot === null && ((debug() && !failSilently)))
console$3.log("Shadow root not found or not added in element yet", element);
return shadowRoot;
}
catch (error) {
if (debug() && !failSilently)
console$3.log("Error while accessing shadow root", element, error);
return null;
}
}
function $$(selector, returnRoots = false) {
return $$recursion(
selector,
document$$.bind(document$2),
document$2,
returnRoots
);
}
function isArrayEmptyStrings(arr) {
return !arr || arr.length === 0 || arr.every(item => item.trim() === "");
}
function executeSvgCommand(
nestedCommands,
rootParent,
resultNodes,
rootParents
) {
const xlinkHref = rootParent.getAttribute("xlink:href") ||
rootParent.getAttribute("href");
if (xlinkHref) {
const matchingElement = document$$(xlinkHref)[0];
if (!matchingElement && debug()) {
console$3.log("No elements found matching", xlinkHref);
return false;
}
if (isArrayEmptyStrings(nestedCommands)) {
const oldRootParents = rootParents.length > 0 ? rootParents : [];
resultNodes.push({
element: matchingElement,
rootParents: [...oldRootParents, rootParent]
});
return false;
}
const next$$ = matchingElement.querySelectorAll.bind(matchingElement);
return {
nextBoundElement: matchingElement,
nestedSelectorsString: nestedCommands.join("^^"),
next$$
};
}
}
function executeShadowRootCommand(nestedCommands, rootParent) {
const shadowRoot = $openOrClosedShadowRoot(rootParent);
if (shadowRoot) {
const {querySelectorAll: shadowRootQuerySelectorAll} = shadowRoot;
const next$$ = shadowRootQuerySelectorAll &&
bind(shadowRootQuerySelectorAll, shadowRoot).bind(shadowRoot);
return {
nextBoundElement: rootParent,
nestedSelectorsString: ":host " + nestedCommands.join("^^"),
next$$
};
}
return false;
}
function $$recursion(
selector,
bound$$,
boundElement,
returnRoots,
rootParents = []
) {
if (selector.includes("^^")) {
const [currentSelector, currentCommand, ...nestedCommands] =
selector.split("^^");
let newRootParents;
let commandFn;
switch (currentCommand) {
case "svg": {
commandFn = executeSvgCommand;
break;
}
case "sh": {
commandFn = executeShadowRootCommand;
break;
}
default: {
if (debug()) {
console$3.log(
currentCommand,
" is not supported. Supported commands are: \n^^sh^^\n^^svg^^"
);
}
return [];
}
}
if (currentSelector.trim() === "")
newRootParents = [boundElement];
else
newRootParents = bound$$(currentSelector);
const resultNodes = [];
for (const rootParent of newRootParents) {
const res =
commandFn(nestedCommands, rootParent, resultNodes, rootParents);
if (!res)
continue;
const {next$$, nestedSelectorsString, nextBoundElement} = res;
const nestedElements = $$recursion(
nestedSelectorsString,
next$$,
nextBoundElement,
returnRoots,
[...rootParents, rootParent]
);
if (nestedElements)
resultNodes.push(...nestedElements);
}
return resultNodes;
}
const foundElements = bound$$(selector);
if (returnRoots) {
return [...foundElements].map(element => (
{element, rootParents: rootParents.length > 0 ? rootParents : []})
);
}
return foundElements;
}
const {assign, setPrototypeOf} = Object$8;
class $XPathExpression extends XPathExpression {
evaluate(...args) {
return setPrototypeOf(
apply$2(super.evaluate, this, args),
XPathResult.prototype
);
}
}
class $XPathEvaluator extends XPathEvaluator {
createExpression(...args) {
return setPrototypeOf(
apply$2(super.createExpression, this, args),
$XPathExpression.prototype
);
}
}
function hideElement(element) {
if (variables$1.hidden.has(element))
return false;
notifyElementHidden(element);
variables$1.hidden.add(element);
let {style} = $(element);
let $style = $(style, "CSSStyleDeclaration");
let properties = $([]);
let {debugCSSProperties} = libEnvironment;
for (let [key, value] of (debugCSSProperties || [["display", "none"]])) {
$style.setProperty(key, value, "important");
properties.push([key, $style.getPropertyValue(key)]);
}
new MutationObserver$3(() => {
for (let [key, value] of properties) {
let propertyValue = $style.getPropertyValue(key);
let propertyPriority = $style.getPropertyPriority(key);
if (propertyValue != value || propertyPriority != "important")
$style.setProperty(key, value, "important");
}
}).observe(element, {attributes: true,
attributeFilter: ["style"]});
return true;
}
function notifyElementHidden(element) {
if (isExtensionContext && typeof checkElement === "function")
checkElement(element);
}
function initQueryAndApply(selector) {
let $selector = selector;
if ($selector.startsWith("xpath(") &&
$selector.endsWith(")")) {
let xpathQuery = $selector.slice(6, -1);
let evaluator = new $XPathEvaluator();
let expression = evaluator.createExpression(xpathQuery, null);
let flag = XPathResult.ORDERED_NODE_SNAPSHOT_TYPE;
return cb => {
if (!cb)
return;
let result = expression.evaluate(document$2, flag, null);
let {snapshotLengt