Chrome Extension Modifying User Agent - google-chrome

Is it possible to modify the user agent from within a chrome extension?
I am developing an extension for web developers (yes I'm aware of Chromes own extension for this).
Any ideas?

Example code changing the User-Agent for an Android one.
var MOBILE_CHROME_USER_AGENT = 'Mozilla/5.0 (Linux; U; Android-4.0.3; en-us; Galaxy Nexus Build/IML74K) AppleWebKit/535.7 (KHTML, like Gecko) CrMo/16.0.912.75 Mobile Safari/535.7';
chrome.webRequest.onBeforeSendHeaders.addListener(
function(details) {
for (var i = 0; i < details.requestHeaders.length; ++i) {
if (details.requestHeaders[i].name === 'User-Agent') {
details.requestHeaders[i].value = MOBILE_CHROME_USER_AGENT;
break;
}
}
return {requestHeaders: details.requestHeaders};
}, {urls: ['<all_urls>']}, ['blocking', 'requestHeaders']);

The WebRequest API is no longer experimental; You can read all about it at its new home:
chrome.webRequest
and yes you can use it to alter the User-Agent header.

There's experimental WebRequest API for these purposes. You can prevent URL requests, change request headers etc. Of course you can't yet upload your extension to Chrome Web Store if your code uses experimental features of Chrome extensions.

Related

click doesn't load the page using chrome mobile simulator for webdriver

trying to work with chrome mobile simulator (iPhone 6) , all the actions work on the web page except for click .It doesn't throw any exceptions but the click doesn't load the next page or submits the form .So no click actions are being performed even though the element is identified.
website link for iphone 6 - www.sherwin-williams.com/painting-contractors
capabilities for iphone 6
USER_AGENT = "Mozilla/5.0 (iPhone; CPU iPhone OS 8_0 like Mac OS X) AppleWebKit/600.1.3 (KHTML, like Gecko) Version/8.0 Mobile/12A4345d Safari/600.1.4";
deviceMetrics.put("width", 375);
deviceMetrics.put("height", 667);
deviceMetrics.put("pixelRatio", 2.0);
mobileEmulation.put("deviceMetrics", deviceMetrics);
mobileEmulation.put("userAgent", USER_AGENT );
options.setExperimentalOption("mobileEmulation", mobileEmulation);
driver = new ChromeDriver(options);
#FindBy(id = "off-canvas-header-trigger)
protected WebElement clicknavbar;
public MobilePage clicknavigation() {
driver.click(clicknavbar, "Unable to click navigation bar");
return this;
}
public boolean click(WebElement element, String errorMessage) {
softAssert.setCause(null);
boolean success = true;
try {
element.click();
} catch (Exception e) {
throw e;
}
}
html dom
issue got resolved by updating chromedriver version to 2.35 from previous version which was 2.34

How to run Selenium WebDriver test cases in Chrome for mobile site

how to run my selenium 'webdriver' with google chrome for mobile site, not getting any clue to run my scripts,
i have user agent for the firefox like and running my test cases easily in firefox for mobile site
FirefoxProfile ffProfile = new FirefoxProfile();
ffProfile.addExtension(new File(CONFIG.getProperty("agentswitcher")));
String samsung3 = "Mozilla/5.0 (Linux; U; Android 4.0.3; de-de; Galaxy S II Build/GRJ22) AppleWebKit/534.30 (KHTML, like Gecko) Version/4.0 Mobile Safari/534.30";
ffProfile.setPreference("general.useragent.override", samsung3);
here agent switcher is the user_agent_switcher-0.7.3-fx+sm.xpi file download it from web
It's very simple.
You need to pass a param of ChromeOptions to constructor of ChromeDriver
The code is the next:
string device = "Samsung Galaxy S4";
ChromeOptions options = new ChromeOptions();
options.EnableMobileEmulation(device);
IWebDriver driver = new ChromeDriver(options);//this will open Chrome in mobile mode
List of available devices you can get from Chrome mobile emulator.
Some of them are: "Apple iPhone 4", "Apple iPhone 6", "Samsung Galaxy S4"
Use below code to launch chrome browser in mobile view
System.setProperty("webdriver.chrome.driver", "/path/to/chromedriver.exe");
Map<String, String> mobileEmulation = new HashMap<>(); mobileEmulation.put("deviceName", "Galaxy S5");
ChromeOptions options = new ChromeOptions(); options.setExperimentalOption("mobileEmulation", mobileEmulation); ChromeDriver driver = new ChromeDriver(options) driver.get("http://google.com");
log.info(driver.getTitle());
driver.quit();

Can I disable Firefox / Chrome components from an addon / extension?

I already made some addons for Firefox and extensions for Chrome, but now I had a crazy idea and I would like to know if I can disable Firefox / Chrome components from an addon / extension.
When I say disable components, I mean something like (mostly FF examples):
Firefox Hello
Pocket (Firefox has now a default integration with Pocket)
History
Favorites
Other installed extensions
Resources like "Print" and "Developer Tools"
Etc.
I've searched for the whole Firefox Addon Developer Hub and I didn't found if I can do something like that. If you know the answer, how can I do that or why I can't?
You don't need to describe why it's (or isn't) possible and how I can achieve that, but in this case provide useful and interesting links.
From Firefox it is very easy to disable other things.
This for example disables an addon by id:
//this checks to see if AdBlock Plus is enabled
AddonManager.getAddonsByIDs(["{d10d0bf8-f5b5-c8b4-a8b2-2b9879e08c5d}"], function ([aAddon1]) {
console.log(aAddon1);
var isAddonEnabled = aAddon1.isActive;
alert('AdBlock plus enabled = ' + isAddonEnabled)
//for other properties see here: https://developer.mozilla.org/en-US/Add-ons/Add-on_Manager/Addon#Required_properties
});
Components are done a little differently, you would have to use nsICategoryManager, this disables the default pdf reader:
https://developer.mozilla.org/en-US/docs/Mozilla/Tech/XPCOM/Reference/Interface/nsICategoryManager#Remarks
var CONTENT_TYPE = 'application/pdf';
// Update the category manager in case the plugins are already loaded.
let categoryManager = Cc['#mozilla.org/categorymanager;1'];
categoryManager.getService(Ci.nsICategoryManager).deleteCategoryEntry('Gecko-Content-Viewers', CONTENT_TYPE, false);
// Update pref manager to prevent plugins from loading in future
var stringTypes = '';
var types = [];
var PREF_DISABLED_PLUGIN_TYPES = 'plugin.disable_full_page_plugin_for_types';
if (Services.prefs.prefHasUserValue(PREF_DISABLED_PLUGIN_TYPES)) {
stringTypes = Services.prefs.getCharPref(PREF_DISABLED_PLUGIN_TYPES);
}
if (stringTypes !== '') {
types = stringTypes.split(',');
}
if (types.indexOf(CONTENT_TYPE) === -1) {
types.push(CONTENT_TYPE);
}
Services.prefs.setCharPref(PREF_DISABLED_PLUGIN_TYPES, types.join(','));

How do I detect Chromium specifically vs. Chrome?

Is there a way to detect if a visitor to my site is running Chromium as opposed to Google Chrome? Even basic UA sniffing (which I know is bad practice) would suffice for my particular case, but it appears that Chromium and Chrome share the same UA string – is that correct? Is there any other way that I can differentiate between the two?
Note:
This no longer works, because now all Chrome-based-navigators have all plugins.
New Chromium-versions do have the PDF-plugin, too.
But they also have Chromium-plugins, so if any plugin starts with "Chromium", it's Chromium:
function isChromium() {
for (var i = 0, u = "Chromium", l = u.length; i < navigator.plugins.length; i++) {
if (navigator.plugins[i].name != null && navigator.plugins[i].name.substr(0, l) === u)
return true;
}
return false;
}
Also, use this to identify Microsoft Chredge (aka. Anaheim)
function isEdg() {
for (var i = 0, u = "Microsoft Edg", l = u.length; i < navigator.plugins.length; i++) {
if (navigator.plugins[i].name != null && navigator.plugins[i].name.substr(0, l) === u)
return true;
}
return false;
}
Chrome ships with a built-in PDF reader, Chromium doesn't.
You could detect this by using JavaScript:
function isChrome() { // Actually, isWithChromePDFReader
for (var i=0; i<navigator.plugins.length; i++)
if (navigator.plugins[i].name == 'Chrome PDF Viewer') return true;
return false;
}
This method is not 100% reliable, because users can copy the PDF reader binary from Chrome to their Chromium directory, see this answer on Ask Ubuntu.
There's almost no difference between Chromium and Chrome (certainly not in the rendering or JavaScript engine), so why do you want to spot the difference?
Starting with Chromium 84 there's a new method called User-Agent Client Hints reference
You can check if the userAgentData property exists and look for brand data. It will return an array that looks something like this.
[{
"brand": " Not;A Brand",
"version": "99"
}, {
"brand": "Google Chrome",
"version": "91"
}, {
"brand": "Chromium",
"version": "91"
}]
userAgentData.brands will contain varying values in a varying order, so don't rely on something appearing at a certain index. Instead check if the property exists in the array.
if (navigator.userAgentData) {
let vendors = window.navigator.userAgentData.brands;
if (vendors.filter(e => e.brand === 'Google Chrome').length > 0) {
console.log('Chrome')
} else {
console.log('Chromium')
}
}
Here is a variation to Paul W.'s answer that works for Chromium version 42 and above:
function isChromium() { // Actually, isWithChromiumPDFReader
for (var i=0; i<navigator.plugins.length; i++)
if (navigator.plugins[i].name == 'Chromium PDF Viewer') return true;
return false;
}
This of course only works if the plugin has not been disabled by the user.
Here is another way, using SpeechSynthesis feature.
Google Chrome Browser ships TTS voices, where Chromium browsers (incl. Brave) do not. Voices can be installed manually, with espeak (on linux) however the Google voices all start with Google, where the manually installed voices do not. As far as I know the Chrome voices are propriety, not free.
The collection of voices is an Array where each voices looks like this:
{
voiceURI: "Google Deutsch",
name: "Google Deutsch",
lang: "de-DE",
localService: false,
default: true
}
We just need to find one who's name/URI starts with Google ...
function hasGoogleVoices() {
return window.speechSynthesis.getVoices()
.some(v => /^google/i.test(v.name));
}
(Tested on Linux for Chrome, Brave, Chromium and Firefox)
Please can someone check Safari and Windows. Thx.
Could not comment on https://stackoverflow.com/a/68428992/14238203 Josh Answer.
On latest Chrome and Chromium (Oct 2021) some of the solutions returns true for both, so I had to find a different solution.
I took https://stackoverflow.com/a/63724166/14238203 fliptopbox code and implmented Josh answer.
const isChrome = navigator.userAgentData.brands.some((v) => /^google/i.test(v.brand));
The issue with Josh answer is that if you try this when just loading a page, the getVoices() returns empty array until all the voices are loaded (page finished loading)
A promise solution to that here - https://stackoverflow.com/a/59786665/14238203
For my use case it was a bit cumbersome with the getVoices() so I used the user agent hints solution.

HTML5 navigator.geolocation in Web Workers

I am trying to move my code for navigator.geolocation in a web worker.
I tried it with Chrome and Safari but getting 'undefined' on
var isGPSSupported = navigator.geolocation;
Frustrated... they said in specification that 'navigator' object should be supported in web workers...
My code is below:
index.js
var gpsWorker = new Worker("app/gpsworker.js");
gpsWorker.onmessage = function (e) {
alert(e.data);
};
gpsWorker.postMessage("Start GPS!");
gpsWorker.onerror = function (e) {
alert("Error in file: " + e.filename + "\nline: " + e.lineno + "\nDescription: " + e.message);
};
gpsworker.js
self.onmessage = function (e) {
initGeoLoc();
}
function initGeoLoc() {
if (navigator.geolocation) {
navigator.geolocation.getCurrentPosition(function (position) {
self.postMessage("Got position!");
});
} else {
self.postMessage("GPS is not supported on this platform.");
}
}
Any hint on what is wrong will be greatly appreciated.
I had similar question as yours before and asked a related question. Now I believe I have the answer to your question (and also one of my related questions).
navigator.geolocation belongs to navigator in the main thread only, but doesn't belong to navigator in the worker thread.
The main reason is that even though the navigator in worker thread looks exactly the same as the one in main thread, those two navigators have independent implementations on the C++ side. That is why navigator.geolocation is not supported in the worker thread.
The related code is in Navigator.idl and WorkerNavigator.idl in Chromium code. You can see that they are two independent interfaces in the .idl files. And they have independent implementations on the C++ side of the binding. Navigator is an attribute of DOMWindow, while WorkerNavigator is an attribute of WorkerGlobalScope.
However, on the JavaScript side, they have the same name: navigator. Since the two navigators are in two different scopes, there is no name conflict. But when using the APIs in JavaScript, people usually expect similar behavior on both main and worker threads if they have the same name. That's how the ambiguity happens.
The 'navigator' object is supported, however it only contains four properties: appName, appVersion, userAgent, and platform.
From looking at your code, it appears you are trying to track the user's location as it changes. You do not have to use web workers to accomplish this. You can simply monitor the user's location on the main thread using watchPosition(), which will automatically notify a callback function whenever the user's location changes:
navigator.geolocation.watchPosition(function(position) {
document.getElementById('currentLat').innerHTML = position.coords.latitude;
document.getElementById('currentLon').innerHTML = position.coords.longitude;
});
Inspecting it in chrome, it appears it definitely doesn't have the geolocation attribute:
WorkerNavigator
appName: "Netscape"
appVersion: "5.0 (Windows NT 6.1) AppleWebKit/537.1 (KHTML, like Gecko) Chrome/22.0.1207.1 Safari/537.1"
onLine: true
platform: "Win32"
userAgent: "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.1 (KHTML, like Gecko) Chrome/22.0.1207.1 Safari/537.1"
__proto__: WorkerNavigator
In Chrome, you can set a breakpoint in your workers. I'd recommend doing this for your errors, its extremely helpful.
Would it not suffice to have the watchPosition(success) in the main-thread postMessage() the new location to your webWorker?