How can we overwrite navigator.getBattery()?
Asked Answered
C

3

2

We are writing a chrome extension that returns a random battery level when the battery level is checked by a site running client-side code for fingerprinting reasons. Sample code that can be used by a site can be seen below.

navigator.getBattery().then(function(battery) {
    console.log(battery.level);
});

We are unable to find documentation regarding how the navigator.getBattery() method can be overwritten to accomplish the goal. The incomplete content-script.js can be seen below.

var navigatorBatteryPrivacy = '(' + function() {
    'use strict';
    var navigator = window.navigator;
    var modifiedNavigator;
    if (Navigator.prototype) {


        modifiedNavigator = Navigator.prototype;

    } else {

        modifiedNavigator = Object.create(navigator);
        Object.defineProperty(window, 'navigator', {
            value: modifiedNavigator,
            configurable: false,
            enumerable: false,
            writable: false
        });
    }


    modifiedNavigator.getBattery = function modifiedGetBattery() {
        return Promise.resolve(new BatteryManager());
    };




} + ')();';

var s = document.createElement('script');
s.textContent = navigatorBatteryPrivacy;
document.documentElement.appendChild(s);
s.remove();

We appreciate the cooperation of the community members.

Cartelize answered 22/9, 2018 at 10:16 Comment(3)
It's a read-only property, I don't think you can overwrite/spoof thoseMumbletypeg
@LucaKiebel I just overwrote it in my Chrome console.Villus
Also make sure to run your content script at document_start.Muskellunge
P
3

Use a content script that injects a script at document_start with the following code -

Object.defineProperty(navigator, "getBattery", {
    value: () => {/*your custom logic goes here*/}
});

Add the following to manifest json.

"content_scripts": [{
    "run_at": "document_start",
    "js": ["contentscript.js"]
}]
Parochialism answered 22/9, 2018 at 10:29 Comment(0)
J
1

needs to be run before executing other scripts on the page

var p = Object.create(BatteryManager).prototype;
Object.defineProperty(p,'level',{enumerable: true, configurable: true, get: ()=> 0.34});
Object.defineProperty(p,'charging',{get: ()=> true});
Object.defineProperty(p,'chargingTime',{get: ()=> Infinity});
Object.defineProperty(p,'dischargingTime',{get: ()=> Infinity});

Object.defineProperty(p,'onchargingchange',{get: ()=> null});
Object.defineProperty(p,'onchargingtimechange',{get: ()=> null});
Object.defineProperty(p,'ondischargingtimechange',{get: ()=> null});
Object.defineProperty(p,'onlevelchange',{get: ()=> null});
Object.defineProperty(navigator, "getBattery", {
   value: () => { return Promise.resolve(p)
   }
});
Janerich answered 12/10, 2021 at 11:5 Comment(0)
V
0

Rather than creating a new navigator object, you can simply replace navigator.getBattery.

var navigatorBatteryPrivacy = "(" + function() {
    navigator.getBattery = function modifiedGetBattery() {
        return Promise.resolve(new BatteryManager());
    };
} + ")();";
Villus answered 22/9, 2018 at 10:31 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.