diff options
author | Ruben Rodriguez <ruben@trisquel.info> | 2022-09-08 20:18:54 -0400 |
---|---|---|
committer | Ruben Rodriguez <ruben@trisquel.info> | 2022-09-08 20:18:54 -0400 |
commit | 5da28b0f8771834ae208d61431d632875e9f8e7d (patch) | |
tree | 688ecaff26197bad8abde617b4947b11d617309e /data/extensions/jsr@javascriptrestrictor/wrappingS-SENSOR-ACCEL.js | |
parent | 4a87716686104266a9cccc2d83cc249e312f3673 (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/wrappingS-SENSOR-ACCEL.js')
-rw-r--r-- | data/extensions/jsr@javascriptrestrictor/wrappingS-SENSOR-ACCEL.js | 451 |
1 files changed, 451 insertions, 0 deletions
diff --git a/data/extensions/jsr@javascriptrestrictor/wrappingS-SENSOR-ACCEL.js b/data/extensions/jsr@javascriptrestrictor/wrappingS-SENSOR-ACCEL.js new file mode 100644 index 0000000..9023c1f --- /dev/null +++ b/data/extensions/jsr@javascriptrestrictor/wrappingS-SENSOR-ACCEL.js @@ -0,0 +1,451 @@ +/** \file + * \brief Wrappers for the Accelerometer Sensor, LinearAccelerationSensor, + * and GravitySensor + * + * \see https://www.w3.org/TR/accelerometer/ + * \see https://www.w3.org/TR/accelerometer/#linearaccelerationsensor + * \see https://www.w3.org/TR/accelerometer/#gravitysensor + * + * \author Copyright (C) 2021 Radek Hranicky + * + * \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 + * \ingroup wrappers + * MOTIVATION + * Readings from the Accelerometer, LinearAccelerationSensor, and GravitySensor + * of the Generic Sensor API should be secured as they provide a potentially + * valuable data for creating fingerprints. There are multiple options. + * A unique fingerprint can be obtained by describing the device's vibrations + * (See https://link.springer.com/chapter/10.1007/978-3-319-30806-7_7). + * Using trajectory inference and matching of the model to map data, one may + * use the readings from the Accelerometer to determing the device's position + * (See https://www.researchgate.net/publication/220990763_ACComplice_Location_ + * inference_using_accelerometers_on_smartphones). + * Accelerometer readings can also be used for determining human walking patterns + * (See https://www.researchgate.net/publication/322835708_Classifying_Human_ + * Walking_Patterns_using_Accelerometer_Data_from_Smartphone). + * + * + * WRAPPING + * The wrapper replaces the "XYZ" getters of the Accelerometer sensor, + * LinearAccelerationSensor, and GravitySensor. The wrapping's goal is to + * simulate a stationary device that can be possibly rotated. The rotation + * of the device is represented by the fake rotation matrix "orient.rotMat". + * + * The GravitySensor should provide readings of gravity acceleration applied + * to the device. This is represented by a vector made of x, y, z portions. + * To get this faked gravity vector for the device, the reference vector + * [0, 0, 9.8] is multipled with the rotation matrix. Wrappers for the + * GravitySensor's getters return x, y, z portions of the fake gravity vector. + * + * Next, the LinearAccelerationSensor should return acceleration values without + * the contribution of gravity. For a stationary device, it should be all zeroes. + * Yet, there could be vibrations that may change values a little bit, e.g., + * spin around -0.1 to +0.1, as seen on the examined devices. This usually does + * not happed with every reading but only in intervals of seconds. And thus, + * after a few seconds we pseudo-randomly change these values. + * + * Finally, the Accelerometer sensor combines the previous two. Our wrappers thus + * return tha values from the LinearAccelerationSensor with the fake gravity + * vector portions added. + * + * + * POSSIBLE IMPROVEMENTS + * Support for simulation of a non-stationary device where the rotation + * can change. Currently, the calculation of the gravity vector is done + * only once by the initDataGenerator() where the reference vector is + * multiplied with the rotation matrix. If orient.rotMat could change, + * the dataGen would have to be updated periodically. + * Moreover, such a change should also be taken into account in wrappers + * for other movement-related sensors (Gyroscope, etc.). + * + */ + + /* + * Create private namespace + */ +(function() { + /* + * \brief Initialization of data for storing sensor readings + */ + var init_data = ` + var currentReading = currentReading || {orig_x: null, orig_y: null, orig_z: null, timestamp: null, + fake_x: null, fake_y: null, fake_z: null, gVector: null}; + var previousReading = previousReading || {orig_x: null, orig_y: null, orig_z: null, timestamp: null, + fake_x: null, fake_y: null, fake_z: null, gVector: null}; + var emulateStationaryDevice = (typeof args === 'undefined') ? true : args[0]; + var debugMode = false; + + const TWOPI = 2 * Math.PI; + `; + + /* + * \brief Property getters of the original sensor object + */ + var orig_getters = ` + var origGetX = Object.getOwnPropertyDescriptor(Accelerometer.prototype, "x").get; + var origGetY = Object.getOwnPropertyDescriptor(Accelerometer.prototype, "y").get; + var origGetZ = Object.getOwnPropertyDescriptor(Accelerometer.prototype, "z").get; + var origGetTimestamp = Object.getOwnPropertyDescriptor(Sensor.prototype, "timestamp").get; + `; + + /* + * \brief Changes the value on the given axis to a new one from the given interval + * + * \param the axis object (min, max, value, and decimalPlaces properties required) + */ + function shake(axis) { + val = sen_prng() * (axis.max - axis.min) + axis.min; + + var precision = Math.pow(10, -1 * axis.decimalPlaces); + if (val < precision) { + val = 0; + } + + if (axis.canBeNegative) { + val *= Math.round(sen_prng()) ? 1 : -1; + } + + if (val == 0) { + axis.value = 0; + } else { + axis.value = fixedNumber(val, axis.decimalPlaces); + } + } + + /* + * \brief The data generator for creating fake accelerometer values + */ + class DataGenerator { + constructor() { + this.NEXT_CHANGE_MS_MIN = 1000; + this.NEXT_CHANGE_MS_MAX = 10000; + + /* Reference gravity vector + * For a non-rotated device lying bottom-down on a flat surface, + * only axis "z" is afected by g. + */ + let referenceGravityVector = [0, 0, 9.8]; + + /* + * For a rotated device, the reference gravity vector needs to be + * multiplied by the rotation matrix. + * Here we calculate and store the device gravity vector + */ + this.gVector = multVectRot(referenceGravityVector, orient.rotMat); + + /* + * Values for the linear acceleration are fluctuating + */ + this.x = { + name: "x", + min: 0.0, + max: 0.11, + decimalPlaces: 1, + canBeNegative: true, + value: null + }; + this.y = { + name: "y", + min: 0.0, + max: 0.11, + decimalPlaces: 1, + canBeNegative: true, + value: null + }; + this.z = { + name: "z", + min: 0.0, + max: 0.11, + decimalPlaces: 1, + canBeNegative: true, + value: null + }; + this.nextChangeTimeX = null; // miliseconds + this.nextChangeTimeY = null; + this.nextChangeTimeZ = null; + } + + /* + * \brief Updates the x/y/z axes values based on the current timestamp + * + * \param Current timestamp from the sensor object + */ + update(currentTimestamp) { + // Simulate the Gyroscope changes + if (this.shouldWeUpdateX(currentTimestamp)) { + shake(this.x); + this.setNextChangeX(currentTimestamp); + }; + if (this.shouldWeUpdateY(currentTimestamp)) { + shake(this.y); + this.setNextChangeY(currentTimestamp); + }; + if (this.shouldWeUpdateZ(currentTimestamp)) { + shake(this.z); + this.setNextChangeZ(currentTimestamp); + }; + } + + /* + * \brief Boolean function that decides if the value on the axis X + * should be updated. Returns true if update is needed. + * + * \param Current timestamp from the sensor object + */ + shouldWeUpdateX(currentTimestamp) { + if (currentTimestamp === null || this.nextChangeTimeX === null) { + return true; + } + if (currentTimestamp >= this.nextChangeTimeX) { + return true; + } else { + return false; + } + } + + /* + * \brief Boolean function that decides if the value on the axis Y + * should be updated. Returns true if update is needed. + * + * \param Current timestamp from the sensor object + */ + shouldWeUpdateY(currentTimestamp) { + if (currentTimestamp === null || this.nextChangeTimeY === null) { + return true; + } + if (currentTimestamp >= this.nextChangeTimeY) { + return true; + } else { + return false; + } + } + + /* + * \brief Boolean function that decides if the value on the axis Z + * should be updated. Returns true if update is needed. + * + * \param Current timestamp from the sensor object + */ + shouldWeUpdateZ(currentTimestamp) { + if (currentTimestamp === null || this.nextChangeTimeZ === null) { + return true; + } + if (currentTimestamp >= this.nextChangeTimeZ) { + return true; + } else { + return false; + } + } + + /* + * \brief Sets the timestamp of the next update of value on the axis X. + * + * \param Current timestamp from the sensor object + */ + setNextChangeX(currentTimestamp) { + let interval_ms = Math.floor( + sen_prng() * (this.NEXT_CHANGE_MS_MAX - this.NEXT_CHANGE_MS_MIN + 1) + + this.NEXT_CHANGE_MS_MIN + ); + this.nextChangeTimeX = currentTimestamp + interval_ms; + } + + /* + * \brief Sets the timestamp of the next update of value on the axis Y. + * + * \param Current timestamp from the sensor object + */ + setNextChangeY(currentTimestamp) { + let interval_ms = Math.floor( + sen_prng() * (this.NEXT_CHANGE_MS_MAX - this.NEXT_CHANGE_MS_MIN + 1) + + this.NEXT_CHANGE_MS_MIN + ); + this.nextChangeTimeY = currentTimestamp + interval_ms; + } + + /* + * \brief Sets the timestamp of the next update of value on the axis Z. + * + * \param Current timestamp from the sensor object + */ + setNextChangeZ(currentTimestamp) { + let interval_ms = Math.floor( + sen_prng() * (this.NEXT_CHANGE_MS_MAX - this.NEXT_CHANGE_MS_MIN + 1) + + this.NEXT_CHANGE_MS_MIN + ); + this.nextChangeTimeZ = currentTimestamp + interval_ms; + } + } + + /* + * \brief Updates the stored (both real and fake) sensor readings + * according to the data from the sensor object. + * + * \param The sensor object + */ + function updateReadings(sensorObject) { + + // We need the original reading's timestamp to see if it differs + // from the previous sample. If so, we need to update the faked x,y,z + let previousTimestamp = previousReading.timestamp; + let currentTimestamp = origGetTimestamp.call(sensorObject); + + if (debugMode) { + // [!] Debug mode: overriding timestamp + // This allows test suites to set a custom timestamp externally + // by modifying the property of the sensor object directly. + currentTimestamp = sensorObject.timestamp; + } + + if (currentTimestamp === previousReading.timestamp) { + // No new reading, nothing to update + return; + } + + // Rotate the readings: previous <- current + previousReading = JSON.parse(JSON.stringify(currentReading)); + + // Update current reading + // NOTE: Original values are also stored for possible future use + currentReading.orig_x = origGetX.call(sensorObject); + currentReading.orig_y = origGetY.call(sensorObject); + currentReading.orig_z = origGetZ.call(sensorObject); + currentReading.timestamp = currentTimestamp; + + dataGenerator.update(currentTimestamp); + + currentReading.fake_x = dataGenerator.x.value; + currentReading.fake_y = dataGenerator.y.value; + currentReading.fake_z = dataGenerator.z.value; + currentReading.fake_gVector = dataGenerator.gVector; + + if (debugMode) { + } + } + + /* + * \brief Initializes the related generators + */ + var generators = ` + // Initialize the data generator, if not initialized before + var dataGenerator = dataGenerator || new DataGenerator(); + `; + + var helping_functions = sensorapi_prng_functions + device_orientation_functions + + DataGenerator + shake + updateReadings; + var hc = init_data + orig_getters + helping_functions + generators; + + var wrappers = [ + { + parent_object: "Accelerometer.prototype", + parent_object_property: "x", + wrapped_objects: [], + helping_code: hc, + post_wrapping_code: [ + { + code_type: "object_properties", + parent_object: "Accelerometer.prototype", + parent_object_property: "x", + wrapped_objects: [], + /** \brief replaces Sensor.prototype.x getter to return a faked value + */ + wrapped_properties: [ + { + property_name: "get", + property_value: ` + function() { + updateReadings(this); + if (this.__proto__.constructor.name === 'GravitySensor') { + return fixedNumber(currentReading.fake_gVector[0], 1); + } else if (this.__proto__.constructor.name === 'LinearAccelerationSensor') { + return fixedNumber(currentReading.fake_x, 1); + } + return fixedNumber(currentReading.fake_x + currentReading.fake_gVector[0], 1); + }`, + }, + ], + } + ], + }, + { + parent_object: "Accelerometer.prototype", + parent_object_property: "y", + wrapped_objects: [], + helping_code: hc, + post_wrapping_code: [ + { + code_type: "object_properties", + parent_object: "Accelerometer.prototype", + parent_object_property: "y", + wrapped_objects: [], + /** \brief replaces Sensor.prototype.y getter to return a faked value + */ + wrapped_properties: [ + { + property_name: "get", + property_value: ` + function() { + updateReadings(this); + if (this.__proto__.constructor.name === 'GravitySensor') { + return fixedNumber(currentReading.fake_gVector[1], 1); + } else if (this.__proto__.constructor.name === 'LinearAccelerationSensor') { + return fixedNumber(currentReading.fake_y, 1); + } + return fixedNumber(currentReading.fake_y + currentReading.fake_gVector[1], 1); + }`, + }, + ], + } + ], + }, + { + parent_object: "Accelerometer.prototype", + parent_object_property: "z", + wrapped_objects: [], + helping_code: hc, + post_wrapping_code: [ + { + code_type: "object_properties", + parent_object: "Accelerometer.prototype", + parent_object_property: "z", + wrapped_objects: [], + /** \brief replaces Sensor.prototype.z getter to return a faked value + */ + wrapped_properties: [ + { + property_name: "get", + property_value: ` + function() { + updateReadings(this); + if (this.__proto__.constructor.name === 'GravitySensor') { + return fixedNumber(currentReading.fake_gVector[2], 1); + } else if (this.__proto__.constructor.name === 'LinearAccelerationSensor') { + return fixedNumber(currentReading.fake_z, 1); + } + return fixedNumber(currentReading.fake_z + currentReading.fake_gVector[2], 1); + }`, + }, + ], + } + ], + }, + ] + add_wrappers(wrappers); +})() |