summaryrefslogtreecommitdiff
path: root/data/extensions/jsr@javascriptrestrictor/fp_code_builders.js
diff options
context:
space:
mode:
authorRuben Rodriguez <ruben@trisquel.info>2022-09-08 20:18:54 -0400
committerRuben Rodriguez <ruben@trisquel.info>2022-09-08 20:18:54 -0400
commit5da28b0f8771834ae208d61431d632875e9f8e7d (patch)
tree688ecaff26197bad8abde617b4947b11d617309e /data/extensions/jsr@javascriptrestrictor/fp_code_builders.js
parent4a87716686104266a9cccc2d83cc249e312f3673 (diff)
Updated extensions:
* Upgraded Privacy Redirect to 1.1.49 and configured to use the 10 most reliable invidious instances * Removed ViewTube * Added torproxy@icecat.gnu based on 'Proxy toggle' extension * Added jShelter 0.11.1 * Upgraded LibreJS to 7.21.0 * Upgraded HTTPS Everywhere to 2021.7.13 * Upgraded SubmitMe to 1.9
Diffstat (limited to 'data/extensions/jsr@javascriptrestrictor/fp_code_builders.js')
-rw-r--r--data/extensions/jsr@javascriptrestrictor/fp_code_builders.js335
1 files changed, 335 insertions, 0 deletions
diff --git a/data/extensions/jsr@javascriptrestrictor/fp_code_builders.js b/data/extensions/jsr@javascriptrestrictor/fp_code_builders.js
new file mode 100644
index 0000000..4378a84
--- /dev/null
+++ b/data/extensions/jsr@javascriptrestrictor/fp_code_builders.js
@@ -0,0 +1,335 @@
+/** \file
+ * \brief Functions that help to automate process of building wrapping code for FPD module
+ *
+ * \author Copyright (C) 2021 Marek Salon
+ *
+ * \license SPDX-License-Identifier: GPL-3.0-or-later
+ */
+// This program is free software: you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+//
+// This program 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 this program. If not, see <https://www.gnu.org/licenses/>.
+//
+
+/** \file
+ *
+ * \brief This file is part of Fingerprint Detector (FPD) and contains helper functions for automated wrappers creation.
+ * File also contains loading routine for FPD configuration files (groups-lvl_X.json, wrappers-lvl_X.json, etc...).
+ *
+ * \ingroup FPD
+ */
+
+//DEF_FPD_FILES_S
+var fp_config_files = ["groups-lvl_0", "groups-lvl_1", "wrappers-lvl_0_1"]
+//DEF_FPD_FILES_E
+
+/**
+ * The object carrying code for builded FPD wrappers
+ */
+var fp_wrapped_codes = {};
+
+/**
+ * Object containing parsed input from JSON configuration files of FPD module.
+ */
+var fp_levels = {};
+
+/**
+ * Additional wrappers for specialized purposes.
+ */
+var additional_wrappers = [
+ {
+ parent_object: "HTMLElement.prototype",
+ parent_object_property: "offsetHeight",
+ wrapped_objects: [],
+ post_wrapping_code: [
+ {
+ code_type: "object_properties",
+ parent_object: "HTMLElement.prototype",
+ parent_object_property: "offsetHeight",
+ wrapped_objects: [
+ {
+ original_name: `
+ Object.getOwnPropertyDescriptor(HTMLElement.prototype, "offsetHeight") ?
+ Object.getOwnPropertyDescriptor(HTMLElement.prototype, "offsetHeight")["get"] :
+ HTMLElement.prototype.offsetHeight
+ `,
+ wrapped_name: "originalD_get"
+ }
+ ],
+ wrapped_properties: [
+ {
+ property_name: "get",
+ property_value: `function() {
+ // workaround - style property is bound to HTMLElement instance, check fontFamily value with every access
+ let font = this.style.fontFamily;
+ updateCount("CSSStyleDeclaration.prototype.fontFamily", "set", [font]);
+ return originalD_get.call(this);
+ }`
+ }
+ ]
+ }
+ ]
+ },
+ {
+ parent_object: "HTMLElement.prototype",
+ parent_object_property: "offsetWidth",
+ wrapped_objects: [],
+ post_wrapping_code: [
+ {
+ code_type: "object_properties",
+ parent_object: "HTMLElement.prototype",
+ parent_object_property: "offsetWidth",
+ wrapped_objects: [
+ {
+ original_name: `
+ Object.getOwnPropertyDescriptor(HTMLElement.prototype, "offsetWidth") ?
+ Object.getOwnPropertyDescriptor(HTMLElement.prototype, "offsetWidth")["get"] :
+ HTMLElement.prototype.offsetWidth
+ `,
+ wrapped_name: "originalD_get"
+ }
+ ],
+ wrapped_properties: [
+ {
+ property_name: "get",
+ property_value: `function() {
+ // workaround - style property is bound to HTMLElement instance, check fontFamily value with every access
+ let font = this.style.fontFamily;
+ updateCount("CSSStyleDeclaration.prototype.fontFamily", "set", [font]);
+ return originalD_get.call(this);
+ }`
+ }
+ ]
+ }
+ ]
+ }
+]
+
+/// \cond (Exclude this section from the doxygen documentation. If this section is not excluded, it is documented as a separate function.)
+{
+ // parse input files into fp_levels for each level, generate wrapping code and initialize FPD module
+ let loadFpdConfig = async () => {
+ for (let file of fp_config_files) {
+ try {
+ let config = JSON.parse(await readFile(browser.runtime.getURL(`fp_config/${file}.json`)));
+ let file_splitted = file.split("-");
+ let file_levels = file_splitted[1].split("_").filter(x => x != 'lvl');
+ fp_levels[file_splitted[0]] = fp_levels[file_splitted[0]] || {};
+ for (let level of file_levels) {
+ fp_levels[file_splitted[0]][level] = config;
+ }
+ }
+ catch (e) {
+ console.error(e);
+ }
+ }
+
+ // merge duplicit entries of the same resource to be wrapped only once
+ let mergeWrappers = (sameResources) => {
+ let mergeGroups = () => {
+ let accArray = [];
+ for (let resource of sameResources) {
+ accArray.push(...resource.groups);
+ }
+ return accArray;
+ }
+
+ return {
+ resource: sameResources[0].resource,
+ type: sameResources[0].type,
+ groups: mergeGroups()
+ }
+ }
+
+ for (let level in fp_levels.wrappers) {
+ let tmpWrappers = {};
+ for (let wrapper of fp_levels.wrappers[level]) {
+ if (!Object.keys(tmpWrappers).includes(wrapper.resource)) {
+ let sameResources = fp_levels.wrappers[level].filter(x => x.resource == wrapper.resource);
+ tmpWrappers[wrapper.resource] = mergeWrappers(sameResources);
+ }
+ }
+ fp_levels.wrappers[level] = Object.values(tmpWrappers);
+ }
+
+ for (let level in fp_levels.wrappers) {
+ // define wrapper for each FPD endpoint (using default JSS definition of wrappers)
+ let tmp_build_wrapping_code = {};
+ for (let wrap_item of fp_levels.wrappers[level]) {
+ if (wrap_item.type == "property") {
+ tmp_build_wrapping_code[wrap_item.resource] = fp_build_property_wrapper(wrap_item);
+ }
+ else if (wrap_item.type == "function") {
+ tmp_build_wrapping_code[wrap_item.resource] = fp_build_function_wrapper(wrap_item);
+ }
+ }
+
+ // if there is an additional wrapper for resource, overwrite default definition with it
+ for (let additional_item of additional_wrappers) {
+ let { parent_object, parent_object_property } = additional_item;
+ let resource = `${parent_object}.${parent_object_property}`;
+ if (resource in tmp_build_wrapping_code) {
+ tmp_build_wrapping_code[resource] = additional_item;
+ }
+ }
+
+ // transform each wrapper to wrapping code and index it in memory for quick access
+ fp_wrapped_codes[level] = {};
+ for (let build_item in tmp_build_wrapping_code) {
+ try {
+ fp_wrapped_codes[level][build_item] = build_code(tmp_build_wrapping_code[build_item]);
+ } catch (e) {
+ console.error(e);
+ fp_wrapped_codes[level][build_item] = "";
+ }
+ }
+ }
+
+ // initialize FPD module (background script and event listeners)
+ initFpd();
+ }
+ loadFpdConfig();
+}
+/// \endcond
+
+/**
+ * The function that appends FPD wrappers into injectable code, if JSS hasn't wrapped certain FPD endpoints already.
+ *
+ * \param code String containing injectable code generated by "generate_code" method.
+ * \param jss_wrappers Array of wrappers defined by JSS level object.
+ * \param fpd_level Identifier of the current FPD level/config.
+ *
+ * \returns Modified injectable code that also contains FPD wrapping code.
+ */
+function fp_update_wrapping_code(code, jss_wrappers, fpd_level) {
+ let fpd_wrappers = Object.keys(fp_wrapped_codes[fpd_level])
+ .filter(key => !jss_wrappers.map(x => x[0]).includes(key))
+ .reduce((obj, key) => {
+ obj[key] = fp_wrapped_codes[fpd_level][key];
+ return obj;
+ }, {});
+ let fpd_code = joinWrappingCode(Object.values(fpd_wrappers));
+ return code.replace("// FPD_S\n", `// FPD_S\n ${fpd_code}`);
+}
+
+/**
+ * The function that creates injectable code specifically for FPD wrappers in case that JSS hasn't wrapped anything.
+ *
+ * \param fpd_level Identifier of the current FPD level/config.
+ *
+ * \returns Injectable code containing only FPD wrapping code.
+ */
+function fp_generate_wrapping_code(fpd_level) {
+ return generate_code("// FPD_S\n" + joinWrappingCode(Object.values(fp_wrapped_codes[fpd_level])) + "\n// FPD_E");
+}
+
+/**
+ * The function splitting resource string into path and name.
+ * For example: "window.navigator.userAgent" => path: "window.navigator", name: "userAgent"
+ *
+ * \param wrappers text String representing full name of resource.
+ *
+ * \returns Object consisting of two properties (path, name) for given resource.
+ */
+function split_resource(text) {
+ var index = text.lastIndexOf('.');
+ return {
+ path: text.slice(0, index),
+ name: text.slice(index + 1)
+ }
+}
+
+/**
+ * The function that constructs implicit property wrapper object from FPD configuration.
+ *
+ * \param wrap_item Single resource object from FPD wrappers definition.
+ *
+ * \returns New declarative property wrapper supported by code_builder (same structure as explicitly defined wrappers).
+ */
+function fp_build_property_wrapper(wrap_item) {
+ // return object initialization
+ var wrapper_object = {};
+
+ // get unique array of property types (set, get), if property not defined => implicit get
+ var propTypes = Array.from(new Set(wrap_item.groups.map(
+ (x) => { return x.property != undefined ? x.property : "get" })));
+
+ // if properties to wrap exist, create property wrapper based on wrap_item input
+ if (propTypes.size != 0) {
+ var resource_splitted = split_resource(wrap_item.resource);
+ wrapper_object = {
+ parent_object: resource_splitted["path"],
+ parent_object_property: resource_splitted["name"],
+ wrapped_objects: [],
+ post_wrapping_code: [
+ {
+ code_type: "object_properties",
+ parent_object: resource_splitted["path"],
+ parent_object_property: resource_splitted["name"],
+ wrapped_objects: [],
+ wrapped_properties: [],
+ }
+ ],
+ };
+
+ // create post_wrapping_code to wrap every property type
+ for (let type of propTypes) {
+
+ // save original resource - get property from descriptor, if do not exists, save it directly
+ wrapper_object.post_wrapping_code[0].wrapped_objects.push({
+ original_name: `
+ Object.getOwnPropertyDescriptor(${resource_splitted["path"]}, "${resource_splitted["name"]}") ?
+ Object.getOwnPropertyDescriptor(${resource_splitted["path"]}, "${resource_splitted["name"]}")["${type}"] :
+ ${type == "get" ? wrap_item.resource : undefined}
+ `,
+ wrapped_name: `originalD_${type}`,
+ });
+
+ // return original property (do not change semantics)
+ wrapper_object.post_wrapping_code[0].wrapped_properties.push({
+ property_name: type,
+ property_value: `
+ originalD_${type}
+ `,
+ })
+ };
+ }
+ return wrapper_object;
+}
+
+/**
+ * The function that constructs implicit function wrapper object from FPD configuration.
+ *
+ * \param wrap_item Single resource object from FPD wrappers definition.
+ *
+ * \returns New declarative function wrapper supported by code_builder (same structure as explicitly defined wrappers).
+ */
+function fp_build_function_wrapper(wrap_item) {
+ var resource_splitted = split_resource(wrap_item.resource);
+
+ var wrapper_object = {
+ parent_object: resource_splitted["path"],
+ parent_object_property: resource_splitted["name"],
+
+ // save original function into variable
+ wrapped_objects: [{
+ original_name: `${resource_splitted["path"]}.${resource_splitted["name"]}`,
+ wrapped_name: `originalF_${resource_splitted["name"]}`
+ }],
+ wrapping_function_args: "...args",
+
+ // call original function on return with same arguments and context (do not change semantics)
+ wrapping_function_body: `
+ return originalF_${resource_splitted["name"]}.call(this, ...args);
+ `,
+ };
+ return wrapper_object;
+}