Overriding Browser API's - javascript

I am developing a webextension in javascript for Firefox, Chrome etc.
It is designed to prevent the users browser from being fingerprinted.
Since the majority of information used to build browser fingerprints comes from javascript API's in the browser itself, is it possible to change/spoof the values that common API's might return from within a webextension/addon?
If this is not directly possible then is there any way to control what values these API's return to the website doing the fingerprinting to protect the users privacy?
Examples of API's I am talking about are:
user agent
screen print
color depth
current resolution
available resolution
device XDPI
device YDPI
plugin list
font list
local storage
session storage
timezone
language
system language
cookies
canvas print

You can try using Object.defineProperty():
The Object.defineProperty() method defines a new property directly on an object, or modifies an existing property on an object, and returns the object.
console.log(window.screen.colorDepth); // 24
Object.defineProperty(window.screen, 'colorDepth', {
value: 'hello world',
configurable: true
});
console.log(window.screen.colorDepth); // hello world
In the above we're using Object.defineProperty to change the value of the property window.screen.colorDepth. This is where you would spoof the values using whatever method you want. You can use this same logic for modifying whichever properties you want to spoof (navigator.userAgent for example)
But there is a separation between the page's global object and the plugins global object. You should be able to overcome that by injecting the script into the document:
var code = function() {
console.log(window.screen.colorDepth); // 24
Object.defineProperty(window.screen, 'colorDepth', {
value: 'hello world',
configurable: true
});
console.log(window.screen.colorDepth); // hello world
};
var script = document.createElement('script');
script.textContent = '(' + code + ')()';
(document.head||document.documentElement).appendChild(script);
See here and here for more info.
You can download a working chrome extension using the above code here (unzip the folder, navigate to chrome://extensions in chrome and drop the folder into the window)

Related

Download Video from URL without opening in chrome browser

I have registered for a course that has roughly 150 videos.
What I have done Uptil NOW:
There is no download button available right now.
In order to get the URL of each video file, I have created the script which I run through Console as below:
The site where I am watching these videos is different than the xxxxx marked site.
e.g. I am watching on linkedin learning and video is on lynda,etc.
console.log(("<h2>"+ document.title)+"</h2>"
+
" click here ");
document.getElementsByClassName("video-next-button")[0].click();
an example of output from above code is:
<h2>Overview of QGIS features: Learning QGIS (2015)</h2>
<a href="https://files3.xxxxx.com/secure/courses/383524/VBR_MP4h264_main_SD/383524_01_01_XR15_Overview.mp4?V0lIWk4afWPs3ejN5lxsCi1SIkGKYcNR_F7ijKuQhDmS1sYUK7Ps5TYBcV-MHzdVTujT5p03HP10F_kqzhwhqi38fhOAPnNJz-dMyvA2-YIpBOI-wGtuOjItlVbRUDn6QUWpwe1sRoAl__IA1zmJn3gPvC7Fu926GViqVdLa3oLB0mxRGa7i> click here </a>
I have replaced domain name with xxxxx
This way I can get cover all videos without clicking next (I would like to know if I can automate this process by using some timeout techniques as well)
each of this link, when clicked, chrome window looks like below:
this way after clicking 3dots -> Download, I can save video individually.
What I want:
Method to save all videos without the need to open individually.
Challenge
To begin with, fetching and saving large binary files is possible when:
The host server's CORS support is enabled.
Accessing the host's network from the same site-origin.
Server-to-Server.
Okay, this would reason why your anchor attempt did not work, in fact, accessing the host's network from your localhost will deny you from accessing the resource's content unless the host server's CORS support is enabled which is unlikely.
Workaround
Alternatively, this will leave us with the other two options, accessing from the same site-origin in particular due to its simplicity, the strategy lies in executing the fetching/saving script from the browser itself, thus, the host server will be gentle with the requests, since they are very similar to the ones coming from the same site.
Steps
Go to the site you wish to download the files from (I used https://www.sample-videos.com).
Right-click the web page and select 'Inspect' (Ctrl + Shift + I).
Finally, switch to the 'Console' tab to start coding.
Code
const downloadVideos = (videos, marker) => {
// it's important to throttle between requests to dodge performance or network issues
const throttleTime = 10000; // in milliseconds; adjust it to suit your hardware/network capabilities
const domain = 'https://www.sample-videos.com'; // site's domain
if (marker < videos.length) {
console.log(`Download initiated for video ${videos[marker].name} # marker:${marker}`);
const anchorElement = document.createElement('a');
anchorElement.setAttribute('href', `${domain}${videos[marker].src}`);
anchorElement.setAttribute('download', videos[marker].name);
document.body.appendChild(anchorElement);
// trigger download manually
anchorElement.click();
anchorElement.remove();
marker += 1;
setTimeout(downloadVideos, throttleTime, videos, marker);
}
};
// assuming all videos are stored in an array, each video must have 'src' and 'name' attributes
const videos = [
{ src: '/video123/mp4/480/big_buck_bunny_480p_30mb.mp4', name: 'video_480p.mp4' },
{ src: '/video123/mp4/720/big_buck_bunny_720p_1mb.mp4', name: 'video_720p.mp4' }
];
// fireup
downloadVideos(videos, 0);
... ahem!

Equivalent of simple storage API for restartless firefox extension

Is there an equivalent to this API or a way to call it from a restartless extension? I need to store a few strings between browser sessions.
I have found this but it seems too complicated for simple string storage. Does the SS API use the same thing behind the scene?
The simple-storage/localStorage APIs suck because of synchronous file I/O.
There are alternatives such as IndexedDB which can be used from chrome/add-on code quite easily.
You can also use localStorage in your add-on (no need to use the SDK simple-storage API), but should not use window.localStorage in overlays because that would be shared between add-ons, and cannot use window.localStorage in bootstrap.js and/or js code modules because there simply is no window. But you can construct a storage object yourself.
function getStorage(uri) {
if (!(uri instanceof Ci.nsIURI)) {
uri = Services.io.newURI(uri, null, null);
}
let principal = Cc["#mozilla.org/scriptsecuritymanager;1"].
getService(Ci.nsIScriptSecurityManager).
getNoAppCodebasePrincipal(uri);
let dsm = Cc["#mozilla.org/dom/localStorage-manager;1"].
getService(Ci.nsIDOMStorageManager);
return dsm.createStorage(principal, "");
}
var s1 = getStorage("chrome://my-addon/content/whatever.xul"); // does not actually have to point to a resource.
The usual limitations of localStorage apply (quotas and such).
BTW: The code also lets you access the localStorage of websites, e.g. getStorage("http://stackoverflow.com/");.
You can import any SDK module into normal restartless extensions this way:
const { devtools } = Cu.import("resource://gre/modules/devtools/Loader.jsm", {});
const { require } = devtools;
let ss = require('sdk/simple-storage');
You could use Session store API (nsISessionStore):
const ss = Cc["#mozilla.org/browser/sessionstore;1"].getService(Ci.nsISessionStore);
ss.setGlobalValue("my-extension-few-strings", "blah blah blah");
const fewStrings = ss.getGlobalValue("my-extension-few-strings");
// fewStrings === "blah blah blah";
ss.deleteGlobalValue("my-extension-few-strings");
Session store is shared across all extensions, so choose unique names for stored values (e.g. prepend all key names with your extension name). And unlike simple-storage and localStorage it's not limited in size.
p.s. setGlobalValue, getGlobalValue, deleteGlobalValue are not documented anywhere.

addthis_widget.js throwing Cannot read property '_pmh' of null error on Android and Chrome

I am using a JavaScript error logging tool to log any JavaScript errors on my mobile site and I am seeing a large number (22,000 in under a month) of this error:
Uncaught TypeError: Cannot read property '_pmh' of null
I can see from the addthis_widget.js code that it is originating from that script.
I can also tell that it only affects mobile Android and Google Chrome browsers, these in particular:
Android 4, Android 4.1, Android 4.2, Chrome 11, Chrome 18, Chrome 25, Chrome 26, Chrome 27, Chrome Mobile 18, Chrome Mobile 25, Chrome Mobile 26
I am using the following external JavaScript include:
http://s7.addthis.com/js/250/addthis_widget.js#username=xa-4b6adff375a64db9
and have the following configuration object set:
<script type="text/javascript">
var addthis_config = {
data_ga_property: 'UA-18721873-1', // real GA profile hidden for privacy purposes
data_ga_social: true
};
</script>
Is there anything I can do to prevent this error from occuring so many times on these browsers?
I have located the cause of this issue and it is down the following code.
if (window.addthis) {
window.addthis = null;
window._adr = null;
window._atc = null;
window._atd = null;
window._ate = null;
window._atr = null;
window._atw = null;
}
This was an attempt to cleanup the objects lying around when moving between pages dynamically to prevent memory issues.
addThis now provide support for this problem, their support department sent me the following link:
http://www.addthis.com/blog/2013/05/07/a-brief-history-of-using-addthis-dynamically/#.Uklx4RCKyas
and the following explanation/information:
Along with other information from my peers and such, I've come up with
the proper code which should be executed when moving from virtual page
to virtual page such as in your mobile application. Rather than
nulling any of the AddThis related objects, they must be left alone.
When the page URL or Title (or any other AddThis configuration option)
that you want to be used by our buttons changes, you should execute
our method:
addthis.update(type, key, value)
It takes the three parameters: type, key, value.
Type is either "share" or "config". The key is the same key you would
set according to our API documentation. What you likely need to know
are just the two keys: "url" and "title". The value is of course the
value you want those options to have.
After you have updated all of the options you need to update using
that method, you need to invoke this method:
addthis.toolbox(cssSelector)
The cssSelector is usually going to be ".addthis_toolbox" but if for
some reason you don't want to refresh all of your toolboxes, you can
be more specific about it.
Once you have made those changes to your code, I believe that our
tools will work properly for you and that there will be no more "null
object" related javascript errors.
You can look at this JSFiddle to see an example of dynamically
changing content: http://jsfiddle.net/j5addthis/r6Utv/
I'm having the same issue, but it appears that there was, at one point, a fix to your specific case above by simply upgrading the script that you're using from addthis to version 3.0 by changing this:
http://s7.addthis.com/js/250/addthis_widget.js#username=xa-4b6adff375a64db9
To this:
http://s7.addthis.com/js/300/addthis_widget.js#username=xa-4b6adff375a64db9
Read more here: http://support.addthis.com/customer/portal/questions/1021465-addthis-widget-js-throwing-cannot-read-property-pmh-of-null-error-on-android-and-chrome
Note though, as I mentioned above, my issue continues to persist even with version 3.0 despite the AddThis help desk stating that should work.

How do I change the browser language with Javascript

I want to access the user browser settings and change the browser language, is this possible using Javascript?
If it's possible, how can I access this? (sample code please)
You can detect, but cannot set.
var lang = navigator.language || navigator.userLanguage;
// navigator.language : Netscape & Firefox
// navigator.userLanguage : Internet Explorer
If you want to output different languages, the best way is to do it server-side. Either:
use an AJAX call to dynamically load the appropriate page
use a session variable to load the initial page correctly
This is impossible and a bad idea. A better idea is to detect the browser's language, which is possible to do reasonably well, and ask the user to change it (assuming the change is absolutely necessary).
No that is not possible. How would you find it if you open a page, and your browser turns Arabic (or some other language you can't read)?
This is possible if you do it from within a Chrome extension.
Check this answer to a similar question & contentScript.js of locale-switcher Chrome extension:
let locale = null;
chrome.storage.local.get(["locale"], result => {
if (result) {
locale = result.locale;
}
if (locale) embedScript();
});
const embedScript = () => {
const code = `
(() => {
Object.defineProperties(Navigator.prototype, {
language: {
value: '${locale}',
configurable: false,
enumerable: true,
writable: false
},
languages: {
value: ['${locale}'],
configurable: false,
enumerable: true,
writable: false
}
});
})();`;
const script = document.createElement("script");
script.textContent = code;
document.documentElement.prepend(script);
script.remove();
};
I'm aware of timing (this question was asked 10 years before this answer) & that would be particularly fun if you are the author of this extension.
If what you actually want to do is detect the language the user is using, which is what you want to do, because nothing will annoy your visitors more that their browser preferences getting changed, on the server-side, read the Accept-Language HTTP request header that all modern browsers send, it should contain all the info you need. If it is absent, assume the language of your largest audience.
Check out RFC2616 Section 14.4 for more information on Accept-Language and it's use.
This is definitely not possible using JavaScript on a web page.
A browser Extension might have the rights to change this - I'm not sure, it will also depend on the browser. However, building such an extension would require a fair amount of skill and work.

Can javascript access a filesystem? [duplicate]

This question already has answers here:
Local file access with JavaScript
(14 answers)
Closed 8 years ago.
I was pretty sure the answer was NO, and hence google gears, adobe AIR, etc.
If I was right, then how does http://tiddlywiki.com work? It is persistent and written in javascript. It is also just a single HTML file that has no external (serverside) dependencies. WTF? Where/how does it store its state?
Tiddlywiki has several methods of saving data, depending on which browser is used. As you could see in the source.
If ActiveX is enabled, it uses Scripting.FileSystemObject.
On Gecko-based browsers, it tries to use UniversalXPConnect.
If Java is enabled, it uses the TiddlySaver Java applet.
If Java LiveConnect is enabled, it tries to use Java's file classes.
HTML5's File[1], FileWriter[2], and FileSystem[3] APIs are available in the latest Developer channel of Google Chrome. The FileSystem API lets you read/write to a sandbox filesystem within a space the browser knows about. You cannot, for example, open 'My Pictures' folder on the user's local FS and read/write to that. That's something in the works, but it won't be ready for a while. Example of writing a file:
window.requestFileSystem(
TEMPORARY, // persistent vs. temporary storage
1024 * 1024, // 1MB. Size (bytes) of needed space
initFs, // success callback
opt_errorHandler // opt. error callback, denial of access
);
function initFs(fs) {
fs.root.getFile('logFile.txt', {create: true}, function(fileEntry) {
fileEntry.createWriter(function(writer) { // FileWriter
writer.onwrite = function(e) {
console.log('Write completed.');
};
writer.onerror = function(e) {
console.log('Write failed: ' + e.toString());
};
var bb = new BlobBuilder();
bb.append('Lorem ipsum');
writer.write(bb.getBlob('text/plain'));
}, errorHandler);
}
}
Check out this HTML5 Storage slide deck for more code snippets.
It uses a java file references like this:
drivers.tiddlySaver = {
name: "tiddlySaver",
deferredInit: function() {
if(!document.applets["TiddlySaver"] && !$.browser.mozilla && !$.browser.msie && document.location.toString().substr(0,5) == "file:") {
$(document.body).append("<applet style='position:absolute;left:-1px' name='TiddlySaver' code='TiddlySaver.class' archive='TiddlySaver.jar' width='1'height='1'></applet>");
}
},
isAvailable: function() {
return !!document.applets["TiddlySaver"];
},
loadFile: function(filePath) {
var r;
try {
if(document.applets["TiddlySaver"]) {
r = document.applets["TiddlySaver"].loadFile(javaUrlToFilename(filePath),"UTF-8");
return (r === undefined || r === null) ? null : String(r);
}
} catch(ex) {
}
return null;
},
saveFile: function(filePath,content) {
try {
if(document.applets["TiddlySaver"])
return document.applets["TiddlySaver"].saveFile(javaUrlToFilename(filePath),"UTF-8",content);
} catch(ex) {
}
return null;
}
}
Technically you can do
netscape.security.PrivilegeManager.enablePrivilege('UniversalBrowserWrite');
in a netscape-compatible browser (Firefox, Mozilla, Netscape), and it will ask the user* whether or not to allow filesystem access, but this is not portable.
*once per browser process
Can javascript access a filesystem?
Not outside of the sandbox area mentioned above, to the best of my knowledge. However, it can access a signed java applet that has callable public methods which can get to all files. I have done it and it works fine and is cross browser.
The signing part is somewhat involved and for professional use you might need to pay for a code signing certificate which authorises your identity. Get it from some place like Verisign. That way users at least know who the applet is written by (if that helps). You can sign it yourself for free but one of those "possible security risk" popups will occur at first use for authorisation by the user.
You would think that such signed applets for file writing would exist already for download but I couldn't find any via searching. If they did, you could just plug it in your page, learn the API and off you go.
The answer is indeed NO. Java applets, and the dreaded ActiveX plugins are usually used if this is required

Categories