Enable Cross-Origin XMLHttpRequest in devtool - javascript

I'm working on a devtool Chrome extension and would like to log all XHR request of the current website. So in my injected script ea "messageback-script" I have this:
(function(open) {
XMLHttpRequest.prototype.open = function(method, url, async) {
console.log('The URL is: ' + url);
};
})(XMLHttpRequest.prototype.open);
And I have given required permissions in the manifest.json:
{
"name": "DevToolsPanel",
"version": "0.1",
"description": "Log XHR requests",
"devtools_page": "devtools.html",
"background": {
"scripts": [
"background.js"
]
},
"permissions": [
"tabs",
"http://*/*",
"https://*/*"
],
"manifest_version": 2
}
The problem is that I don't see anything in the console log (blank). What am I doing wrong?

Having examined the code you are using, I can say that this script is evaluated via chrome.tabs.executeScript, making it a Content Script.
Content Scripts live in an isolated context, and as such modifying the XHR prototype only affects XHR in your content script(s). There's a canonical question describing this problem and workarounds.
However, since you're writing a devtools extension, you have a simpler solution via chrome.devtools.inspectedWindow.eval(), which directly executes code in the page's own context.
// In the devtool panel code
chrome.devtools.inspectedWindow.eval("/* Your code here*/");

Related

Firefox Extension / Webextensions: Why doesn't the MDN example of Connection Based Messaging work?

This is the first time I read about writing Firefox extensions.
What I need is obviously only viable via WebExtensions and both a background and a contentscript. I actually only want to write all open tabs as links in a new tab and then File->Save it. Another alternative Idea was to put it into a JSON Object and save that through a dialog, then I probably could even spare the contentscript but I haven't found anything in the API to download a JSON Object via asking the user to download it via Download Dialog.
Whatever. I think I need to communicate with the content-script then.
I tried to run the following example, but it is not working. When I load the manifest file and open the debugger for extensions, it doesn't log anything and nothing has happened except that the variables myPort and portFromCS seem to be declared without any value.
https://developer.mozilla.org/en-US/docs/Mozilla/Add-ons/WebExtensions/Content_scripts#connection-based_messaging
// manifest.json
{
"manifest_version": 2,
"name": "Save Open Tabs",
"version": "1.0",
"description": "Save my tabs",
"background": {
"scripts": ["background.js"]
},
"content_scripts": [
{
"matches": ["*://*/*"],
"js": ["content.js"]
}
],
"permissions": [
"activeTab",
"tabs"
]
}
// content.js
let myPort=browser.runtime.connect({name:"port-from-cs"});
myPort.postMessage({greeting: "hello from content script"});
myPort.onMessage.addListener((m) => {
console.log("In content script, received message from background script: ");
console.log(m.greeting);
});
// background.js
let portFromCS;
function connected(p) {
portFromCS = p;
portFromCS.postMessage({greeting: "hi there content script!"});
portFromCS.onMessage.addListener((m) => {
portFromCS.postMessage({greeting: "In background script, received message from content script:" + m.greeting});
});
}
browser.runtime.onConnect.addListener(connected);
Why doesn't the example work? Maybe wrong URL matching in the manifest file?

How do I use Chrome webrequest API on an extension?

Alright, Im fairly new to making chrome extensions in general and I want to know how to intercept a tag and make a site run a different javascript file when the script is called. I have an extension made to test this out and try to figure it out myself, but it has not worked. When I type in the url of the file to replace, it redirects me to the file that I want it to, but the tag won't redirect to it or if it is, it's not running any of the code from the file. Please help?
content.js
chrome.webRequest.onBeforeRequest.addListener(
function(details) {
if( details.url == "http://www.bellum.io/js/attackCooldown.js" )
return {redirectUrl: "http://yourjavascript.com/1177311921/alertjs.js" };
},
{urls: ["*://www.bellum.io/*.js"]},
["blocking"]);
manifest.json
{
"name": "Simple Webrequest Test",
"version": "0.1",
"description": "Webrequest Test",
"manifest_version": 2,
"permissions": [
"<all_urls>","webRequest","webRequestBlocking","http://*/*"
],
"background": {
"scripts": ["content.js"],
"persistent": true
}
}

Chrome extension: load and execute external script

I have trouble loading and executing external js-script into my chrome extension. Looks the same as this question, but I still cant't figure out why it doesn't work in my case.
The idea is that I want to have in my content script some default function which should parse a web-page content. And for some specific web-pages I want to load and use specific parsers, so I try to load proper js-script for a wep-page, and this script shoud extend functionality of default parser.
By now I try only execute code from external script, but have such error: Unchecked runtime.lastError while running tabs.executeScript: No source code or file specified at Object.callback
This is my manifest.json:
{
"name": "Extension name",
"version": "1.2",
"description": "My chrome extension",
"browser_action": {
"default_popup": "popup.html",
},
"content_scripts": [{
"css": [
"style.css"
],
"js": [
"bower_components/jquery/dist/jquery.js",
"bower_components/bootstrap/dist/js/bootstrap.js",
"content.js"
],
"matches": ["*://*/*"]
}],
"web_accessible_resources": [
"frame.html",
"logo-48.png"
],
"icons": {
"16": "logo-16.png",
"48": "logo-48.png",
"128": "logo-128.png"
},
"permissions": [
"tabs",
"storage",
"http://*/",
"https://*/"
],
"manifest_version": 2
}
This is popup.html
<!doctype html>
<html>
<head>
<title>Title</title>
<script src="popup.js"></script>
</head>
<body>
<ul>
<li>Some link</li>
</ul>
</body>
</html>
And in popup.js i execute scrip like this:
chrome.tabs.query({active: true, currentWindow: true}, function(tabs) {
chrome.tabs.executeScript(tabs[0].id, {file: "http://127.0.0.1:8000/static/plugin/somesite.js"});
});
What am I dong wrong, did I miss something? Or should I use another approach to solve the issue?
Running scripts from external sources like you try is forbidden by google chrome and will block or even not publish your extension. All scripts must be in the extension. But there is a solution,
from google chrome doc:
The restriction against resources loaded over HTTP applies only to
those resources which are directly executed. You're still free, for
example, to make XMLHTTPRequest connections to any origin you like;
the default policy doesn't restrict connect-src or any of the other
CSP directives in any way.
If you need badly an external source, you can do a XML HTTP request and use the eval to the content. Here is a part of code from google doc:
var xhr = new XMLHttpRequest();
xhr.open("GET", "http://127.0.0.1:8000/static/plugin/somesite.js", true);
xhr.onreadystatechange = function() {
if (xhr.readyState == 4) {
// WARNING! Might be evaluating an evil script!
var resp = eval("(" + xhr.responseText + ")");
// Or this if it's work
chrome.tabs.executeScript(tabs[0].id, {code: xhr.responseText});
}
}
xhr.send();
or you can use some library, $.get() with jquery or $http with angularjs.
if you add eval in your code you must add in manifest.json this:
"content_security_policy": "script-src 'self' 'unsafe-eval'; object-src 'self'"`,
As per the discussion here: https://groups.google.com/a/chromium.org/forum/#!topic/chromium-extensions/LIH7LGXeQHo,
Running scripts from external sources may cause your extension to be unpublished or blocked.
Just providing another approach, you could make an ajax call to the content script then call chrome.tabs.executeScript
chrome.tabs.query({active: true, currentWindow: true}, function(tabs) {
$.get("http://127.0.0.1:8000/static/plugin/somesite.js", function(result) {
chrome.tabs.executeScript(tabs[0].id, {code: result});
}, "text");
});
The 'file' option for executeScript only relates to files embedded in your extension. I know, the documentation isn't clear on that and while it might work with URLs, it sounds like a hack, not a feature. In order to load scripts from external sources into your active page, you usually have to execute a script that creates a script tag inside the DOM of the loaded document there.
I feel I have answered parts of this question before here: Why is chrome.tabs.executeScript() necessary to change the current website DOM and how can I use jQuery to achieve the same effect?
To summarize:
1) in order to have access to web pages from the extension, you need to add permissions for it:
"permissions" : [
"tabs",
[...]
"http://*/*",
"https://*/*" ],
2) you need to execute some sort of code that creates the DOM script element that loads what you need:
chrome.tabs.executeScript(tab.id, {
code : 'var script=document.createElement(\'script\');' +
'script.onload=function() { /*do something in the page after the script was loaded*/ };' +
'script.src=\'http://127.0.0.1:8000/static/plugin/somesite.js\';' +
'document.body.appendChild(script);'
}, function (returnedValue) {
// do something in the extension context after the code was executed
});
Take a look at the remex function in the link above, which I think solves a lot of the ugliness of javascript written as a string as here.

Chrome extension that acts only when clicked on certain webpages

I'm trying to get my Chrome extension to pop up an alert when the user is on http://google.com/ and clicks on the extension icon.
I have the following manifest:
{
"manifest_version": 2,
"name": "One Megahurt",
"version": "0.1",
"permissions": [
"activeTab"
],
"background": {
"scripts": ["bg.js"],
"persistent": false
},
"browser_action": {
"default_icon": "icon.png"
}
}
and this is bg.js:
chrome.browserAction.onClicked.addListener(function(tab) {
alert('Test!');
})
This code will allow popup an alert on any website, as I don't have any restrictions on which websites this works on. I tried using
if(tab.url === "https://google.com/")
between the first and second lines, but that didn't work.
I'm not sure if I should even be using a background script rather than a content script. I looked in Google's examples and tried using the implementation in "Page action by URL", but that didn't work for me either.
Any help would be appreciated. I should note that I don't really care about the specific issues with the URL--google.com is merely an example. I want to learn to use this for other projects and websites.
EDIT: Adding urls to permissions doesn't restrict which websites the alert pops up on, either.
I ended up using page actions for my solution, per Felix King's suggestion. In retrospect, this was the best solution to use because it doesn't load the extension on every page and cause browser slowdowns (as far as I know).
In addition to adding domains to permissions in the manifest, add a the following code to a background.js.
// When the extension is installed or upgraded ...
chrome.runtime.onInstalled.addListener(function() {
// Replace all rules ...
chrome.declarativeContent.onPageChanged.removeRules(undefined, function() {
// With a new rule ...
chrome.declarativeContent.onPageChanged.addRules([
{
// That fires when a page's URL matches one of the following ...
conditions: [
new chrome.declarativeContent.PageStateMatcher({
pageUrl: { urlMatches: 'http://google.com/' }, // use https if necessary or add another line to match for both
}),
new chrome.declarativeContent.PageStateMatcher({
pageUrl: { urlMatches: 'http://facebook.com/*' },
}) // continue with more urls if needed
],
// And shows the extension's page action.
actions: [ new chrome.declarativeContent.ShowPageAction()]
}
]);
});
});
chrome.pageAction.onClicked.addListener(function(tab) {
chrome.tabs.executeScript(null, { file: "script.js" });
});
Key sections to add in manifest.js are:
"background": {
"scripts": ["res/background.js"],
"persistent": false
}
&
"permissions": [
"declarativeContent", "tabs", "activeTab", "http://google.com", "http://facebook.com/*"
]
I don't have much experience with this, but looking at the example manifests that I've seen, they usually have the a list of domains under permissions. I'm betting that if you used:
"permissions": ["http://www.google.com/", "https://www.google.com/", https://google.com, https://google.com],
it would only run the code on the permissible pages.
Pulled example from:
http://developer.chrome.com/extensions/overview
More detailed info here:
http://developer.chrome.com/extensions/declare_permissions

Communication between scripts in Chrome Extension

I know there are many variations of this question already in existence here, but none of them seem to work for me.
Details:
I'm writing an extension that pulls some email data from emails you send in gmail. In order to achieve this I am using this version of Gmailr https://github.com/joscha/gmailr.
In effect, I have three content scripts: Gmailr.js and main.js (which are pretty much identical to those in the link above) allow me to pull out the information I'm looking for. Then content.js I use to send a message to the background page of the extension.
The problem is that from gmailr.js and main.js I cannot use any of the Chrome APIs, and I'm not really sure why, so I can't send messages from these back to the background page.
That is why I made content.js which can communicate with the background page. However, it does not seem to be able to see anything the other content scripts do. For example, main.js inserts a div at the top of the page. When I try to attach an event listener to a button in this div from content.js, I am told that no such element exists.
How can I get the data pulled out by main.js to be seen by content.js? (I also tried to put the data in local storage, then trigger a custom event listener to tell content.js to read local storage, but no luck because they don't seem to be able to hear each other's event being triggered).
Any insight or alternatives are much appreciated.
(I can post code if necessary, but it's fragmented and long)
My manifest file:
{
"manifest_version": 2,
"name": "Email extractor",
"description": "Extracts data from emails",
"version": "1.0",
"background": {
"script": "background.js"
},
"content_scripts": [
{
"matches": [
"*://mail.google.com/*",
"*://*/*"
],
"js": [
"lib/yepnope.js/yepnope.1.5.4-min.js",
"lib/bootstrap.js",
"main.js",
"gmailr.js",
"content.js"
],
"css": [
"main.css"
],
"run_at": "document_end"
}
],
"permissions": [
"tabs",
"storage",
"background",
"*://mail.google.com/*",
"*://*/*"
],
"browser_action": {
"default_icon": "img/icon.png",
"default_popup": "popup.html"
},
"web_accessible_resources" : [
"writeForm.js",
"disp.js",
"/calendar/jsDatePick.min.1.3.js",
"/calendar/jsDatePick_ltr.min.css",
"lib/gmailr.js",
"lib/jquery-bbq/jquery.ba-bbq.min.js",
"content.js",
"main.js",
"background.js"
]
}
This is main.js:
Gmailr.init(function(G) {
sender = G.emailAddress();
G.insertTop($("<div id='gmailr'><span></span> <span id='status'></span>)");
el = document.getElementById("testid");
el.addEventListener('click', mg, false);
var status = function(msg) {
G.$('#gmailr #status').html(msg); };
G.observe(Gmailr.EVENT_COMPOSE, function(details) {
....
status(" user: " + user);
console.log('user:', user);
//now try to send a message to the background page
//this always returns the error that method sendMessage does not exist for undefined
chrome.runtime.sendMessage({greeting: "test from gmailr"}, function(response) {
console.log("did it send?");
});
});
});
gmailr.js is quite long and is also not my own code but it can be seen here: http://pastebin.com/pK4EG9vh
Hi perhaps 3 likely reason to your problem :
The way you send messages to bgp from main.js and gmailr.js are perhaps wrong because you must arrive to communicate from any content script to your bgp. (in your manifest content script key the gmailr.js is missing). Show us your code it would help.
You seems to have a problem with the moment you search from content.js to access to the element created in main.js. Do you try to access your element with the jQuery $("").on() method ? A simple test must be to declare a function in one cs and to use it in another. If it's not working it's a manifest problem. The order you declare .js file in manifest content script key is important also.
try to in the manifest content script array "run_at":"document_end"
Hope it help !

Categories

Resources